1. Ucitavanje podataka APR-a

Ucitacemo dva csv fajla, jedan sadrzi starije datume do 2013. godine dok drugi sadrzi novije datume od 2014. godine pa na dalje. Uvezivanje AOP-a po novom i starom kontnom okviru je vec uradjeno i sacuvano u data dva csv fajla. Sami fajlovi ne sadrze AOP-e!!! Razlog je što ne bi mogli da se spoje u jedan fajl budući da AOP-i po starom i novom kontnom okviru nisu mapirani jedana na jedan i samim tim ne bi mogli da se “nalepe” jedan na drugi u cilju dobijanja jednog data.frame-a jer bi imali razlicit broj AOP-a (citaj kolona), fajlovi medjutim sadrze proracunata finansijska racija. Fajlovi sadrze finansijska racija koja su sracunata iz premapiranih iz AOP-a dva kontna okvira (novi i stari kontni okvir). Za detaljniji pregled, uvid u pojedinacne AOP-e pogledati fajlove iz foldera ove analize, fajlovi ce se nalaziti u “~\Early warning\Bottom Up\Korak 3\Pokazatelji” gde ~ predstavlja adresu na kojoj je postavljen folder.
Dodatno pojasnjenje o toliko spominjanim AOP-ima:

U APR bazi su sve pozicije iz bilansa stanja, bilansa uspeha, tokova gotovine, statistickih podataka o preduzecu (statisticki aneks) tretirane kao AOP pozicije, tako na primer broj zaposlenih datog preduzeca mozemo naci u polju AOP 605 za taj maticni broj, ili na primer vrednost stalne imovine iz bilansa stanja se nalazi u polju AOP 001. Medjutim usled menjanja kontnog okvira novi AOP-i sada imaju 4 umesto 3 cifre tako da gore navedane dve varijable se sada nalaze pod AOP-ima 9005 i 0002 respektivno. Medjutim nemoguce je premapirati sve AOP-e po starom nacinu izvestavanja sa AOP-ima po novom nacinu izvestavanja jedan na jedan pa je samim tim bilo i nemoguce prikazati tabela sa varijablama koje ucestvuju u proracunu finansijskih racija, vec su samo prikazani finansijski raciji kao krajnji rezultat.

Cilj je spojiti ova dva csv fajla u jedan. Ucitamo finansijska racija do 2013. godine:

Pokazatelji_stari <- read_delim("C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 3/Pokazatelji/Pokazatelji stari.csv",";", escape_double = FALSE, col_types = cols(Datum = col_date(format = "%m-%d-%Y")), locale = locale(encoding = "ASCII"), trim_ws = TRUE, progress =FALSE)
gc()

Ucitamo finansijska racija posle 2013. godine

Pokazatelji_novi <-
  read_delim(
  "C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 3/Pokazatelji/Pokazatelji novi.csv",
  ";",
  escape_double = FALSE,
  col_types = cols(Datum = col_date(format = "%m-%d-%Y")),
  locale = locale(encoding = "ASCII"),
  trim_ws = TRUE,
  progress =F 
  )
  gc()

Spajamo tabele Pokazatelji_stari i Pokazatelji_novi u jednu tabelu, ove dve tabele su ustvari predstavljale proracunata finansijska racija. Tabele su dobijene prethodnom analitikom i obradom podataka u excelu jer nije bilo moguce drugacije.. Pokrećemo read_KA4_RK_data funkciju za pripremanje KA4 i RK izvestaja. Kreiranje NBS_data funkcije je vec ranije opisano u scriptu ‘~\Early warning\Bottom Up\Korak 4\Early warning\nbs_data_prep.R’ koji sadrzi sustinski isti kod koji i funkcija read_KA4_RK_data.

APR_data <- rbind.data.frame(Pokazatelji_stari, Pokazatelji_novi)
rm(Pokazatelji_stari , Pokazatelji_novi)
gc()


source("nbs_data_prep_function.R")
KA4_url = "C:/Users/milos.cipovic/Desktop/Baze podataka/K4 i APR i NPL/KA4_podaci.txt"
RK_url = "C:/Users/milos.cipovic/Desktop/Baze podataka/K4 i APR i NPL/RK_novi.txt"
NBS_data <- read_KA4_RK_data(KA4_url, RK_url, consequtive_difolt=F)

Spajamo APR i NBS podatke i izbacujemo kolonu NazivSektor jer pravi probleme pri eksportu. Postoji sifrovana verzija ove kolone tako da smo u redu, prezivecemo bez nje. Tako da sada imamo pocetnu tabelu sa podacima koje poseduje NBS o duznicima koji se nalaze u bazi APR-a. Od podataka koje poseduje NBS najveci znacaj nam predstavlja indikator difolta koji nam govori da li ce posmatrani duznik sa sracunatim finansijskim racijima iz APR baze otici u difolt za dve godine ili ne.

c = merge(
  NBS_data,
  APR_data,
  by.x = c("MAT_BR_DUZNIKA", "DATUM.x"),
  by.y = c("Jmb", "Datum")
  )
  #rm(APR_data,NBS_data)
  c = as.data.table(c)
  c[, NazivSektor := NULL]

Kao prvi korak u daljoj analizi potrebno je pre svega obratiti paznju na logicnost unesenih vrednosti kao i na nedostajuce vrednosti, tj. proracunati procenat nedostajucih vrednosti. Nelogicnosti je najlakse proveriti pregledom sumarnih statistika tako da ce nam sledeca tabela pomoci u tome.

2. Preliminarna analiza podataka

Tabela 1. prikazuje aritmeticku sredinu, trimovanu vrednost iste, zatim medijanu, standardnu devijaciju, treci i cetvrti statisticki moment, minimalnu i maksimalnu vrednost kao i u poslednjem redu procenat nedostajucih vrednosti. U toku pripreme podataka u excelu pojedini raciji nisu mogli biti sracunati usled nedostajanja AOP-a za datu opservaciju, posledicno racio date observacije ce imati vrednost ili #N/A ili #DIV/0!. Ove dve vrednosti cemo u nastavku tretirati kao nedostajuce jer one to u svojoj prirodi i jesu. Ovde smo ih zamenili nedostajucim NA vrednostima u R-u.

#zamenjujem #DIV/0! i #N/A sa difoltnom vrednosti za nedostajuce vrednosti u R-u
b <- c
b <- as.data.frame(b)
for (i in 21:50) {
  temp <- b[, i]
  temp[temp == "#N/A" | temp == "#DIV/0!"] <- NA
  b[, i] <- temp
  b[, i] <- as.numeric(b[, i])
}
#sklanjam nepotrebne tabele da oslobodim memoriju jer mora se...kao i svuda do sada
rm(temp,i,KA4_url,RK_url,read_KA4_RK_data,APR_data)
#kreiram duplikat tabele na kom cu da daljeradim i zadrzavam samo bitne kolone,
#tj. neke ce mi biti potrebne kasnije ali za njih sam siguran da su ok jer sam ih kreirao i vec proverio
#u proceduri kreiranja podataka iz bankarskog sektora
b <- data.table(b)
clean_b <- b[, c(1, 4, 2, 9, 5, 7, 14, 16:50)]
#kreiram funkciju za proracun summary statistika
my.summary <- function(x, arg=T){
  x<-as.matrix(x)
  n<-nrow(x)
  data.frame(mean=mean(x, na.rm=arg),
    Trimmed_mean=mean(x,trim = 0.1,na.rm=arg),
    sd=sd(x, na.rm=arg),
    median=median(x, na.rm=arg),
    skewness=e1071::skewness(x,na.rm=arg),
    kurtosis=e1071::kurtosis(x,na.rm=arg),
    min=min(x, na.rm=arg),
    max=max(x,na.rm=arg), 
    First_quartile=quantile(x,0.25,na.rm=arg),
    Third_quartile=quantile(x,0.75,na.rm=arg),
    n=length(x),
    NAspercent=round(sum(as.numeric(is.na(x))/n)*100,1)
    )
}
#kreiram sumarnu tabelu
summary_table1 <- sapply(clean_b[, 11:42], my.summary, arg = T)
#printujem je u notebook
tr_summary_table1 <- t(summary_table1)
formatRound(
  datatable(tr_summary_table1, caption = "Tabela 1.:Sumarni prikaz",
            filter = 'none'),
  columns = colnames(tr_summary_table1)
)

2.1 Nelogicni unosi

U ovom koraku je potrebno pre svega pregledati kategoricke varijable za nelogicne unose, naime, primeceno je da varijabla koja bi trebalo da oznacava velicinu duznika i uzima vrednosti od 1 do 4 sadrzi vrednosti koje su znacajno vece1, takodje, malo je verovatno da je prosecan broj zaposlenih iznosi 7613. Uvidom u podatke doslo se do zakljucka da su date nelogicnosti rezultat razlike u strukturi izvestaja finansijskih institucija i ostalih lica koja su duzna da podatke unose u APR bazu, tako da AOP 602 kod finansijskih institucija ne predstavlja sifru velicine, isto vazi i za polje koje oznacava sifru broja zaposlenih. Daljim uvidom dolazi se do jos nekih saznanja u konzistentnosti AOP-a 602 koji oznacava velicinu lica, naime, otkriveno je jos jedno polje u bazi koju NBS poseduje, a koje nosi informacije o velicini lica, ovo polje nema sifru AOP-a. Posle provere podataka koje posedujemo i njihovim uporedjivanjem sa vrednostima sa APR sajta opredelili smo se za AOP 602. Prethodno opisana dva polja su se u pojedinim slucajevima razlikovala, zbog toga je i izvrsena analiza. Naime, pomenuto polje koje se nalazi u pivot tabelama (nacin na koji NBS ima pristup APR bazi) je u odredjenom broju slucajeva prikazivalo podatke od prethodne godine. Ovo je slucaj samo sa starim nacinom izvestavanja, dakle do 2013. godine!
Nastavljamo sa analizom tako sto cemo izbaciti iz tabele observacije sa vrednostima u koloni Velicina vecim od 4 i manjim od 1 i ponovo pregledati strukturu sumarne tabele. Naknadno, izbacicemo sva lica koja ne pripadaju grupi “Privrednih drustava i zadruga” obzirom da narusavaju homogenost uzorka kao i da im AOP pozicije nisu mapirane kao Privrednim drustavima i zadrugama pa su samim tim te observacije i glavni uzrok nekonzistentnosti u podacima.

Uvidom u Tabelu 2. i polja Velicina i Broj zaposlenih vidimo da su srednja vrednost, minimum i maksimum u prihvatljivim granicama. Posmatranje ostalih varijabli bi zahtevalo detaljniju analizu svake od njih ponaosob. Ovaj korak ce biti uradjen kasnije u univariate analizi tako da ce sada biti preskocen.

#ucitavam unapred pripremljenu tabelu koja nam za posmatrani mb i godinu daje njegovu pripadnost odredjenom sektoru, tj. govori nam iz kojeg je finansijskog izvestaja data observacija u APR-u
gc()
           used  (Mb) gc trigger  (Mb)  max used  (Mb)
Ncells  3162980  84.5   22333286 596.4  18586441 496.4
Vcells 16162926 123.4  100972256 770.4 126212344 963.0
Pravna_forma <-
  read_delim(
  "C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 5/Pravna forma.csv",
  "|",
  escape_double = FALSE,
  trim_ws = TRUE,
  col_types = cols(Datum = col_date(format = "%Y")),
  progress = FALSE
  )
#merdzujem poidatke sa clean_b, tj. preciscavam clean_b tako sto posto merdzujem zadrzim samo one sa 
#sa sifrom 14000 sto predstavlja "Privredna drustava i zadruge"
clean_b <-
  merge(
  clean_b,
  Pravna_forma,
  by.x = c("DATUM.x", "MAT_BR_DUZNIKA"),
  by.y = c("Datum1", "Jmb")
  )
clean_b <-
  clean_b[Sifra == 1400][, c("Naziv", "Sifra", "NazivPravnogLica") := NULL]
  #izbacim vrednosti velicina koje su vece od 4, double check inace ne bi smelo da smanji broj redova
clean_b <- clean_b[Velicina <= 4 & Velicina > 0]
#ponovo kreiram data.frame summary_table
summary_table <- sapply(clean_b[, 11:42], my.summary, arg = T)
#transponujem
tr_summary_table <- t(summary_table)
#printujem tabelu
formatRound(
            datatable(
                      tr_summary_table,
                      caption = "Tabela 2.:Sumarni prikaz bez banaka i ostalih finansijskih institucija",
                      filter = 'none',
                      extensions = 'Buttons', 
                      options = list(
                                     pageLength=13,
                                     dom = 'Bfrtip',
                                     buttons = c(
                                                  'copy',
                                                  'csv',
                                                  'excel'
                                                  )
                                     )  
                      ),
            columns = colnames(tr_summary_table)
           )

2.2 Nedostajuce vrednosti

Tretiranje nedostajucih vrednosti kao korak u razvoju modela nosi dodatnu tezinu imajuci u vidu da ce biti potrebno tretirati nedostajuce vrednosti i u procesu samog predvidjanja solventnosti banke (a to je krajnji cilj ove analize) posto je model evaluiran. Samim tim, uvidom u literaturu o najboljim praksama tretmana nedostajucih observacija odlucujemo se za sledeci postupak koji je predlozen u knjizi Developing, Validating and Using Internal Ratings:

  • Red observacije se brise ukoliko nedostaje vise od 75% podataka u njemu
  • Kolona varijable se brise ukoliko imaju vise od 10% nedostajucih vrednosti2
  • Ukoliko nedostaje manje od 10% observacije posmatrane varijable vrsi se imputacija (zamena) observacija medijanima varijabli. Na ovaj nacin se izbegava osetljivost na autlajere koju poseduje srednja vrednost. Pri cemu se medijana posebno proracunava za zdrave a posebno za duznike u statusu neizmirenja obaveza. Ovo, medjutim nije slucaj kod validacionog uzorka, kao takav on ne bi trebao da sadrzi nikakvu informaciju o tome da li ce posmatrani duznik u buducnosti prestati da izmiruje svoje obaveze, samim tim u validacionom uzorku kao vrednost inputacije koristimo medijanu komplet varijable, nezavisno od toga da li pripada solventnim ili nesolventnim duznicima.
  • Indikatori se transformisu u kategoricke varijable ukoliko postoji apriori znanje o njihovom znacaju i ukoliko ne postoje proksi indikatori koji bi zamenili posmatrani indikator.

Varijable koje predstavljaju problem u smislu procenata nedostajanja su:

  • Racio_novcane_likvidnosti_(Cash_ratio) - ova varijabla je na granici po gorenavedenim kriterijumima
  • Racio_obrta_potrazivanja_od_kupaca
  • Racio_obrta_poslovne_imovine
  • Rast_EBITDA
  • Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja - ova varijabla je na granici po gorenavedenim kriterijumima
  • Rast_prihoda_od_prodaje
  • Pokrice_neto_kamata

Zapazamo da se brisanje nedostajucih observacija preporucuje tek posto su ispunjeni odredjeni uslovi bez obzira na velicinu uzorka, brisanje nedostajucih observacija bi generalno trebalo da bude poslednja opcija pri ciscenju podataka.
Jos jedna cinjenica ce imati udeo u izboru varijabli. Pre svega cetiri pokazatelja u listi su dinamicki i prikazuju stopu rasta odredjene velicine, cime se gubi jedna (prva) godina observacija, samim tim ova cetiri pokazatelja ce u prvoj godini imati sve nedostajuce vrednosti. Navodimo ove racije:

  • Racio obrta potraživanja od kupaca;
  • Racio obrta poslovne imovine;
  • Rast EBITDA;
  • Rast prihoda od prodaje.

Odluka o brisanju ili zadrzavanju ovih varijabli ce prevashodno zavisiti od njihove diskriminativne moci pa zatim od gore navedenih kriterijuma. Dodatno pojasnjavamo da bi zadrzavanje ovih varijabli skratilo citav uzorak za prvu godinu observacija, pa ce i velicina uzorka biti presudan faktor.

Pre primene gore navedenih postupaka vazno je navesti da cemo mi raditi tri modela, u zavisnosti od velicine duznika. Sama podela ce biti izvrsena na osnovu varijable Velicina koja razvrstava lica prema unapred utvrdjenim kriterijumima APR-a videti APR/“Критеријуми за разврставање и граничне вредности за 2016. годину”. U cilju uzimanja u obzir velicine izlozenosti koristicemo i varijablu koja predsavlja udeo izlozenosti posmatranog duznika u kapitalu banke koja je prema njemu izlozena. Ova varijabla ce biti naknadno sracunata i ima za cilj da uzme u obzir razlicit tretman prema duzniku prema njegovoj velicini posmatrano sa stanovnistva banke. Buduci da su odredjeni duznici zaduzeni kod vise banaka posmatrace se samo one banke u kojima je dati duznik najvise zaduzen. Ovo je ujedno i rezultat ranije obrade podataka iz KA4 i RK obrasca (videti skript “~Early warning\nbs_data_prep.R”) gde su o ovim slucajevima visestruke izlozenosti sacuvane observacija kod banaka prema kojima poseduju najveca dugovanja. Pre pocetka univariate analize potrebno je proracunati vec spomenuti udeo izlozenosti posmatranog duznika u regulatornom kapitalu banke. To cemo uraditi tako sto cemo inportovati vec pripremljenu tabelu sa serijom vrednosti regulatornog kapitala banaka.

#ucitavam seriju re4gulatornog kapitala za banke
regulatory_capital <- read_delim(
  "C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 5/regulatory_capital.csv",
  ";",
  escape_double = FALSE,
  col_types = cols(Datum = col_date(format = "%d.%m.%Y")),
  trim_ws = TRUE
)
#prilepljujem je za clean_b tabelu
clean_b <-
  merge(
  clean_b,
  regulatory_capital,
  by.x = c("DATUM.x", "MATICNI_BROJ.x"),
  by.y = c("Datum", "MB")
  )
#proracunavam udeo izlozenosti i odstranjujem kolone viska koje su dosle sa tabelom regulatory_capital
clean_b <-
  clean_b[, udeo_u_kapitalu := (IZLOZENOST.x / Brojilac) * 1000]#skalirano zbog numerike
  clean_b <- clean_b[, c("Brojilac", "Imenilac", "Pokazatelj") := NULL]
#cistim smece
  rm(
    b,
    Pravna_forma,
    regulatory_capital,
    summary_table,
    summary_table1,
    tr_summary_table
    )
    gc()
           used  (Mb) gc trigger  (Mb)  max used  (Mb)
Ncells  3163510  84.5   17866628 477.1  18586441 496.4
Vcells 13546759 103.4   80777804 616.3 126212344 963.0

Na kraju pogledajmo tabelu ciscenja podataka:

Tabela 3.: Pregled obrade podataka od pocetnih pa do podataka koji ulaze

Tabela 3.: Pregled obrade podataka od pocetnih pa do podataka koji ulaze

3. “Univariate” analiza


Do sada nismo jos uvek razmatrali kontinualne varijable, razlog je bio sto uzorak jos uvek nije bio podeljen na tri poduzorka u zavisnosti od velicine duznika. Pre pocetka univariate analize razdvojicemo uzorak na tri dela. Posebno ce se evaluirati modeli za mikro i mala, srednja i velika preduzeca. Takodje, tretman nedostajucih vrednosti je samo deskriptivno naveden u smislu metodoloskog pravca u kom ce se ici pri obradi. Sve ove analize i one koje slede ce se obaviti pojedinacno za svaku grupu duznika ponaosob. Pre nego sto se uzorak razdvoji, u ovoj sekciji, ukratko ce biti opisati raciji koji su korisceni, njihova ekonomska logika i ocekivanu vezu sa verovatnocom difolta, jer ce se isti set racija koristiti u sva tri slucaja. Po opisu racija, u nastavku ove sekcije, ce se ispitati broj nedostajucih vrednosti i njihov tretman, prisutnost autlajera i njihov tretman, radna hipoteza, monotonost, moc diskriminacije i korelacija za svaki od tri modela. Svi prethodno navedeni postupci imaju za cilj sto bolju pred selekciju varijabli pred ulzak u zavrsnu fazu multivariate analizu gde ce stepwise procedurom biti izabrani konacni modeli

3.1 Finansijski raciji, ekonomska logika i radna hipoteza

Kao polazna osnova poslo se od pet grupa pokazatelja koji bi, idealno, trebalo da nam daju informaciju o:

  • Likvidnosti
  • Solventnosti
  • Profitabilnosti
  • Poslovne aktivnosti
  • Ostali pokazatelji koje je tesko svrstati

Pokazatelji, njihova pripadnost grupi i hipoteza ekonomske logicnosti njihove relacije sa verovatnocom nastupanja neizmirenja obaveza je prikazana u sledecoj tabeli:

Tabela 4.: Polazni raciji koji ulaze u univariate analizu

Tabela 4.: Polazni raciji koji ulaze u univariate analizu

3.2 “Univariate” analiza

Razdvajamo uzorak na tri podgrupe:

#kreiram tri nove tabele sa kojima dalje radim
small <- clean_b[Velicina <= 2, ]
medium <- clean_b[Velicina == 3, ]
large <- clean_b[Velicina == 4, ]
#brisem preostale medjukorake
rm(c, NBS_data)
gc()
          used (Mb) gc trigger  (Mb)  max used  (Mb)
Ncells 1547158 41.4   14293302 381.7  18586441 496.4
Vcells 9455548 72.2   64622243 493.1 126212344 963.0

Prvo ćemo detaljno analizirati velika preduzeca (podaci large) počevši od svih gore navedenih koraka u analizi, tako da će ovaj deo imati tri podgrupe, zavisno od same veličine dužnika. Samim tim i krećemo u detaljnu analizu sada…

Univariate analiza velikih preduzeća

Potrebno je pre svega razdvojiti uzorak na validacioni i estimacioni. U nacelu pravilo je da se uzorak deli na 70:30 na stranu estimacije, medjutim ukoliko kuburimo sa podacima Lemeshow u svom kursu o logistickoj regresiji argumentuje da je mnogo bitnije da imamo kompletniji uzorak za estimaciju, tako da cemo se voditi ovom logikom i u nasem slucaju.
Pa, pocnimo.

#izracunam broj redova
broj.red.lrge<-nrow(large)
broj.difolta.lrge<-sum(as.numeric(large$default.y==1))
procenat.difolta<-broj.difolta.lrge/broj.red.lrge

Dakle u najboljem slucaju, ne racunajuci missing value imamo 155 difolta, sto nam deluje kao jedva dovoljno, ukoliko bismo zadrzali 30% bili bismo na granici. Medjutim da bismo se osigurali zadrzacemo 75%, time opet imamo dovoljno difolta za validaciju (oko 40), ovde sam se vodio savetom profesora Lemeshow-a koji kaze da se u ovoj situaciji uvek pokusa zadovoljiti training sample. S druge strane racio nesolventnih u ukupnim duznicima moze imati razlicite vrednosti, tj. ne postoji konsenzus u literaturi o ovoj vrednosti. Ovde biramo da zadrzimo trenutan racio u uzorku tako da cemo uzeti 75% od (solventnih i nesolventnih) duznika zajedno i raditi estimaciju na njemu. Ovim postupkom smo izbegli postupak kalibracije jer smo u training uzorku zadrzali stvarnu frekvenciju defaulta, citaj, verovatnocu defoulta. Jedan problem koji se moze potencijalno javiti je validnost Hosmer–Lemeshow testa sa 40 difolta.

set.seed(60)
#zbog reprodukcije
sample.lrg <-
sample(broj.red.lrge, size = round(0.75 * broj.red.lrge, 0))
lrge.training <- large[sample.lrg, ]
lrge.test <- large[-sample.lrg, ]

Testiranje radne hipoteze, diskriminativnosti, korelacione matrice

Jos jednom cemo pregledati varijable:

#rpivotTable(lrge.training)
summary_table<-t(sapply(lrge.training[,11:43],my.summary,arg=T))
tr_summary_table<-t(summary_table)
formatRound(
            datatable(
                      summary_table,caption = "Tabela 3.:Sumarni prikaz",
                      filter = 'none'
                      ),
            columns = colnames(summary_table)
           )

Generalna preporuka je da se radna hipoteza testira pre tretmana nedostajućih vrednosti budući da će se nedostajuće vrednosti popunjavati uslovno od stanja solventnosti duznika. Samim tim ovde cemo kao prvi vid selekcije ispitati radnu hipotezu kako kontinualnih tako i kategorickih varijabli. Počećemo sa kontinualnim3 i analizu raditi u paru sa proverom diskriminativnosti varijabli. Još u Tabeli 3 vidimo velika odstupanja srednje vrednosti od medijane i trimovanog proseka, buduci da je prosek kao mera centralne tendencije osetljiva na autlajere odlucujemo se da posmatramo medijanu i trimovan prosek, samim tim mogucnost t testa otpada. Dalje, sledeci preporuke iz literature ovaj deo analize osloniti na posmatranje box plotova i bice dopunjen diskriminativnom analizom AUROC-a. Pri testiranju korelacija prag selekcije postavljamo na 0.5 i od dve biramo onu varijablu koja ima vecu diskriminacionu moc.

Kod kategorickih varijabli posmatracemo tabele frekvencija tamo gde to bude imalo smisla i sprovesti Chi-squared test. Ovom prilikom potrebno je i pregrupisati ove varijable tako da budu zadovoljeni kriterijumi:

  • broj difolta po kategoriji kategoricke varijable mora biti minimum 5
  • ukupan broj duznika po kategoriji kategoricke varijable mora biti veci od sto
  • pravilo 1 u 10, za svakih 10 difolta možemo dodati jednu objašnjavajuću, ovo pravilo nam sluzi samo kao vodilja
  • default rate mora biti statisticki razlicit od default rate-a ukupnog uzorka, inace se vrsi pregrupacija
  • iako cemo ispitati hipotezu sagledavanjem tabela frekvencija, poslednju rec ce nam dati sami model i njegove p vrednosti, odnosno likelihood ratio test

Prvo pregledajmo samu distribuciju jos jednom, mada su neke stvari vec jasne iz Tabele 3 hajde ipak da pogledamo.
Prvo kreiramo funkciju za plotiranje: qq plota, box plota, poredjenja gustina verovatnoce (kernela empiriskih distribucija verovatnoce) i konacno za proveru diskriminacije ROC krive.

#delimo uzorak na kontinualne i kategoricke
lrge.training.continualne<-lrge.training[,c(7,6,11,13:43)]
lrge.training.kategoricke<-lrge.training[,c(7,8,9,10,12)]
lrge.test.continualne<-lrge.test[,c(7,6,11,13:43)]
lrge.test.kategoricke<-lrge.test[,c(7,8,9,10,12)]
ploting<-function(dataframe, predictor_col, default_column_col,n=3){
  
  #transformacija podataka 
  dataframe=as.data.frame(dataframe)
  data<-data.frame(predictor=dataframe[,predictor_col],
                   default_column=factor(dataframe[,default_column_col]))
  data<-na.omit(data)
  
#density plot#####################
  density<-ggplot(data, aes(predictor, fill=factor( default_column))) + 
  geom_density(alpha=.5) + 
  scale_fill_manual(values = c('#999999','#E69F00')) + 
  theme(legend.position = "none")+xlim(quantile(data$predictor,c(0.05,0.95),na.rm = T))
#boxplot############################
box_plot<-ggplot(data, aes(y=predictor, x= default_column, fill=default_column))+
  geom_boxplot(alpha=0.5)
  # compute lower and upper whiskers
ylim1 = boxplot.stats(data$predictor)$stats[c(1, 5)]
  # scale y limits based on ylim1
box_plot = box_plot + coord_cartesian(ylim = ylim1*n)+ 
  scale_fill_manual(values = c('#999999','#E69F00'))
#roc curve plot#######################
ROC_plot <-
  ggplot(data, aes(m = predictor, d = as.numeric(default_column))) + geom_roc() +
  geom_abline(intercept = 0,
              slope = 1,
              color = 'red')
result <- auc(data$default_column, data$predictor)
a = paste("Area under the curve:",
          round(ci(result)[[1]], 3),
          ", ",
          round(result, 3),
          ", ",
          round(ci(result)[[3]], 3))
ROC_plot <- ROC_plot + labs(title = a)
#QQ plot
qs = seq(0.001, 0.999, by=0.001)
df.qs = data.frame(quantile.P = qs,
                   q.val.Normal = qnorm(qs,mean(data$predictor),sd(data$predictor)),
                   q.val.X = quantile(data$predictor,qs))
QQ_plot=ggplot(df.qs, aes(q.val.Normal, q.val.X))+
  geom_point(col='#999999', cex=2)+
  geom_line(col='#999999', size=0.75)+
  geom_abline(position="identity")
plot_grid(density,box_plot,ROC_plot,QQ_plot,align = "h", ncol = 4)
}

Krećemo sa opisom svake varijable ponaosob:

Neprekidne promenljive:

Udeo ispravke u ukupnim kreditima


#definisem funkciju za plotovanje
ploting(lrge.training,6,7)
Ignoring unknown parameters: positionRemoved 63 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

Vidimo da distribucije odstupaju daleko od normalne, dalje preklapanje distribucija solventnih u nesolventnih duznika je razocaravajuce, postoji 7 autlajera koji imaju nelogicne vrednosti koji vuku poreklo iz rk obrasca. Iako box plot pokazuje odredjeni stepen diskriminacije u smislu da su solventni duznici manje ispravljeni od nesolventnih, generalno ROC kriva pokazuje da je diskriminacija marginalna iako je znacajna na nivou poverenaj od 95%, ipak, znacajnost je marginalna. Autlajeri ima ih, ima ih mnogo. Buduci da ce slicno biti i sa ostalim varijablama kreiramo taksativan opis u vidu buleta za svaku varijablu kao sto sledi za ovu:

  • Radna hipoteza-nismo postavili radnu hipotezu za ovu varijablu
  • Diskriminativnost -ne postoji na 95% sigurnosti
  • autlajeri - naravno ima ih ima
  • normalnost - ma da…

Broj zaposlenih


#definisem funkciju za plotovanje
ploting(lrge.training,11,7)
Ignoring unknown parameters: positionRemoved 125 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nismo postavili radnu hipotezu za ovu varijablu
  • Diskriminativnost - nema je
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Rigorozni racio redukovane (monetarne) likvidnosti


#definisem funkciju za plotovanje
ploting(lrge.training,13,7)
Ignoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Racio novcane likvidnosti (Cash_ratio)


#definisem funkciju za plotovanje
ploting(lrge.training,14,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti i obecava!!!
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Opsti racio likvidnosti


#definisem funkciju za plotovanje
ploting(lrge.training,15,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - nema na 95% znacajnosti i to ti je!!!
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Stepen_zaduzenosti


#definisem funkciju za plotovanje
ploting(lrge.training,16,7)
Ignoring unknown parameters: positionRemoved 120 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti!!!
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Interest Coverage Ratio


#definisem funkciju za plotovanje
ploting(lrge.training,17,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti i ok je, moze da prodje, mada krivuda sto nije dobro!!!
  • autlajeri - naravno ima ih
  • normalnost - ma da, ali bar lici na nesto normalno…

Racio pokrica obrtne imovine


#definisem funkciju za plotovanje
ploting(lrge.training,18,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti i ok je, solidno!!!
  • autlajeri - naravno ima ih
  • normalnost - ma da

Racio obrta potrazivanja od kupaca


#definisem funkciju za plotovanje
ploting(lrge.training,19,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - nema je 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - ma da, vise kao \(\tilde\chi^2\)nost hihihi, kapiras hi kao hi distribucija :) …

Racio obrta poslovne imovine


#definisem funkciju za plotovanje
ploting(lrge.training,20,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti i ok je, moze da prodje, mada krivuda sto nije dobro!!!
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Gotovinski ciklus 1


#definisem funkciju za plotovanje
ploting(lrge.training,21,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena, veci difolt kod manjih vrednosti, zasto pitam se
  • Diskriminativnost - ima na 95% znacajnosti i ok je, moze da prodje, mada krivuda sto nije dobro!!!
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme vezivanja zaliha


#definisem funkciju za plotovanje
ploting(lrge.training,22,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - nema na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme kreditiranja kupaca


#definisem funkciju za plotovanje
ploting(lrge.training,23,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - nema na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme naplate potraživanja


#definisem funkciju za plotovanje
ploting(lrge.training,24,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme plaćanja dobavljačima


#definisem funkciju za plotovanje
ploting(lrge.training,25,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena, veci difolt kod manjih vrednosti, ipak cemo je uzeti, jer može ekonomski da se objasni rezultat
  • Diskriminativnost - ima na 95% znacajnosti suprotan znak, ono sto bi moglo praviti problem je promena diskriminativnosti kod poslednje cetvrtine distribucije
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Asset turnover


#definisem funkciju za plotovanje
ploting(lrge.training,26,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veca verovatnoca difolta kod manje medijane
  • Diskriminativnost - nema na 95% znacajnosti, ipak cemo je uzeti, zbog diskriminativnosti u manjim vrednostima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Rast EBITDA


#definisem funkciju za plotovanje
ploting(lrge.training,27,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veca verovatnoca difolta kod manje medijane
  • Diskriminativnost - na granici na 95% znacajnosti, uzecemo, mada menja diskriminativnost, videcemo posle multivariata
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Stopa prinosa na sopstveni kapital pre oporezivanja


#definisem funkciju za plotovanje
ploting(lrge.training,28,7)
Ignoring unknown parameters: positionRemoved 120 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-ne znam koji mu je djavo ali evo ovde cemo medijana zdravog je -90.6642634 a nesolventnog je -96.1808463 sto odgovara radnoj hipotezi
  • Diskriminativnost - znacajno na 95% znacajnosti, uzecemo
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Stopa prinosa na ukupna sredstva pre oporezivanja


#definisem funkciju za plotovanje
ploting(lrge.training,29,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-ne znam koji mu je djavo ali evo ovde cemo medijana zdravog je -97.142369 a nesolventnog je -99.5386016 sto odgovara radnoj hipotezi
  • Diskriminativnost - znacajno na 95% znacajnosti, mua
  • autlajeri - naravno ima ih
  • normalnost - jedan od blizih…

Basic Earnings Power Ratio


#definisem funkciju za plotovanje
ploting(lrge.training,30,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je, veci difolt sa manjom vrednoscu
  • Diskriminativnost - ima na 95% znacajnosti, mua
  • autlajeri - naravno ima ih
  • normalnost - jook…

Rast prihoda od prodaje


#definisem funkciju za plotovanje
ploting(lrge.training,31,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena je, nema vidljive razlike
  • Diskriminativnost - nije znacajna na 95% znacajnosti, kandidat za kategoricku
  • autlajeri - naravno ima ih
  • normalnost - jook…

Pokriće neto kamata


#definisem funkciju za plotovanje
ploting(lrge.training,32,7)
Ignoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je mada nema vidljive razlike zbog autlajera
  • Diskriminativnost - nije znacajna na 95% znacajnosti, medjutim ROC ima s oblik sto znaci da postoji diskriminativnost obrnutog smera na vecim i manjim vrednostima, medjutim ovo znaci i da odnos sa verovatnocom default-a nije monoton, kandidat za kategoricku
  • autlajeri - naravno ima ih
  • normalnost - jook…

Cena tuđih izvora sredstava


#definisem funkciju za plotovanje
ploting(lrge.training,33,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je, nema vidljive razlike
  • Diskriminativnost - nije znacajna na 95% znacajnosti, medjutim ROC ima s oblik sto znaci da postoji diskriminativnost obrnutog smera na vecim i manjim vrednostima, medjutim ovo znaci i da odnos sa verovatnocom default-a nije monoton
  • autlajeri - naravno ima ih
  • normalnost - jook…

T1


#definisem funkciju za plotovanje
ploting(lrge.training,34,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - znacajna na 95% znacajnosti, medjutim brine monotonost, moze da prodje
  • autlajeri - naravno ima ih
  • normalnost - jook…

T2


#definisem funkciju za plotovanje
ploting(lrge.training,35,7)
Ignoring unknown parameters: positionRemoved 63 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - znacajna na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - jook…

T3


#definisem funkciju za plotovanje
ploting(lrge.training,36,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - znacajna na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - jook…

T4


#definisem funkciju za plotovanje
ploting(lrge.training,37,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - masterpiece
  • autlajeri - naravno ima ih
  • normalnost - jook…

T5


#definisem funkciju za plotovanje
ploting(lrge.training,38,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - nema
  • autlajeri - naravno ima ih
  • normalnost - jook…

T21


#definisem funkciju za plotovanje
ploting(lrge.training,39,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena
  • Diskriminativnost - nema, za malo
  • autlajeri - naravno ima ih
  • normalnost - jook…

Altman Z-score 1


#definisem funkciju za plotovanje
ploting(lrge.training,40,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - masterpiece
  • autlajeri - naravno ima ih
  • normalnost - jook…

Altman Z-score 2


#definisem funkciju za plotovanje
ploting(lrge.training,41,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - masterpiece
  • autlajeri - naravno ima ih
  • normalnost - jook…

Altman Z-score 3


#definisem funkciju za plotovanje
ploting(lrge.training,42,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - masterpiece
  • autlajeri - naravno ima ih
  • normalnost - jook…

Udeo u kapitalu banke


#definisem funkciju za plotovanje
ploting(lrge.training,43,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je, veci udeo losiji su u proseku
  • Diskriminativnost - za vece vrednosti da
  • autlajeri - naravno ima ih
  • normalnost - jook…

Korelaciona matrica

Kao dodatni kriterijum selekcije uzimamo i korelacionu matricu. Vodicemo se pre svega diskriminativnom moci koju posmatramo prema AUROC vrednosti kao prvim kriterijumom pri izboru izmedju dve varijable sa velikim stepenom korelacije.
U tabeli 5. ispod vidimo da najvecu diskriminacionu moc poseduje varijabla T14 odmah iza koje je ALtman 1.

#proracun
cor=cor(lrge.training.continualne[,c(-1,-31,-32,-33)], use = "complete.obs")
#dodajemo AUROC kao dodatnu kolonu pored varijable
corr_summary<-function (predictor){
  response=factor(lrge.training.continualne[[1]])
suppressMessages(auc(response, as.numeric(predictor)))
}
auc_sumarno<-sapply(lrge.training.continualne[,c(-1,-31,-32,-33)], corr_summary)
kor_diskr<-(cbind(auc_sumarno,cor)) 
formatRound(
            datatable(
                      kor_diskr,caption = "Tabela 5.:Sumarni prikaz",
                      filter = 'none'
                      ),
            columns = colnames(kor_diskr)
           )

Ovde kreiram funkciju koja ce da filtrira varijable po kriterijumu korelacije. Naime, po ugledu na 4 kao kriterijum granice koeficijenta korelacije preko koje ne bismo smeli prelaziti uzecemo vrednost od 0.5 koji ce u sprezi sa AUROC vrednosti selektirati jednu od dve varijable. Konacan izbor varijabli se vidi u korelacionoj tabeli ispod.

#assuming that table is n x (n+1) matrix where first column is AUROC value and the rest n x n is correlation matrix 
corr_ellimination<-function(table1, ro=0.5){
  table=table1
  AUROC<-table[,1]
  table<-table[order(table[,1],decreasing = T),][,-1]
  table.temp=as.data.frame(table)
  for(i in 1:ncol(table)){#kolona
    for(j in 1:nrow(table)){#red
      #browser()
      if(abs(table[i,j])>ro & abs(table[i,j])<1){
        row.name=rownames(table)[i]
        if(sum(row.name==colnames(table.temp))==0) next
        col.name=colnames(table)[j]
        table.temp=table.temp[,col.name!=colnames(table.temp)]
        table.temp=table.temp[col.name!=row.names(table.temp),]
      }
    }
  }
  
  AUROC=AUROC[rownames(table.temp)]
  
  table.temp=cbind(AUROC,table.temp)
  table.temp<-table.temp[AUROC>0.55,]
  table.temp<-table.temp[,rownames(table.temp)]
  
  table.temp[order(rownames(table.temp)),order(colnames(table.temp))]
  AUROC=AUROC[rownames(table.temp)]
  table.temp=cbind(AUROC,table.temp)
}
clean_cor<-corr_ellimination(kor_diskr)
knitr::kable(clean_cor, caption = "Tabela 6. skracena korelaciona tabela koja sadrzi varijable nad kojima ce se vrsiti dalja analiza")
AUROC T14 Racio_novcane_likvidnosti_(Cash_ratio) Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja Stepen_zaduzenosti Racio_pokrica_obrtne_imovine Gotovinski_ciklus_1 Cena_tudjih_izvora_sredstava Vreme_placanja_dobavljacima Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja Vreme_naplate_potrazivanja Rigorozni_racio_redukovane_(monetarne)_likvidnosti Racio_obrta_poslovne_imovine Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio) udeo_u_kapitalu Vreme_kreditiranja_kupaca Rast_EBITDA T21
T14 0.6930996 1.0000000 0.2380564 0.0861365 -0.0492862 0.0279108 0.0528058 -0.0924748 -0.0132031 0.0125315 0.0152887 0.4168406 -0.1516384 0.0558360 -0.0844406 -0.0054643 0.0118250 -0.1011643
Racio_novcane_likvidnosti_(Cash_ratio) 0.6874731 0.2380564 1.0000000 0.1759795 -0.0344113 0.0701974 0.0620004 -0.1533594 -0.0008854 0.0106273 -0.0354183 0.3810735 -0.0267154 0.1808397 -0.0718441 -0.0419165 0.0142587 0.0995163
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja 0.6688459 0.0861365 0.1759795 1.0000000 -0.0529346 0.1277511 0.1320325 -0.1426838 0.0324431 0.2194009 -0.0583805 0.1852934 0.3427016 0.3524184 -0.0880921 -0.1147123 0.2206145 0.1758942
Stepen_zaduzenosti 0.6497292 -0.0492862 -0.0344113 -0.0529346 1.0000000 -0.0090003 0.0001976 0.0854998 -0.0070604 -0.0146694 -0.0089752 -0.0267447 0.0458866 -0.0274399 0.0305530 -0.0173417 0.0006459 0.0528638
Racio_pokrica_obrtne_imovine 0.6384214 0.0279108 0.0701974 0.1277511 -0.0090003 1.0000000 0.0688290 0.0090351 -0.1150341 0.0364006 0.1176060 0.1870060 0.0951495 0.0880883 -0.0747342 -0.2800573 0.0164206 0.1993162
Gotovinski_ciklus_1 0.6293838 0.0528058 0.0620004 0.1320325 0.0001976 0.0688290 1.0000000 -0.0001707 -0.3308074 0.0268798 -0.4595382 0.0517380 0.0901639 0.0508694 0.0523599 -0.2583952 0.0290077 -0.1819115
Cena_tudjih_izvora_sredstava 0.6209256 -0.0924748 -0.1533594 -0.1426838 0.0854998 0.0090351 -0.0001707 1.0000000 -0.0231550 -0.0157811 0.0317831 -0.0514815 -0.1306944 -0.0442208 0.0891322 0.0013485 -0.0565529 0.0813129
Vreme_placanja_dobavljacima 0.6062135 -0.0132031 -0.0008854 0.0324431 -0.0070604 -0.1150341 -0.3308074 -0.0231550 1.0000000 0.0035517 0.2513761 -0.0089706 -0.0478035 -0.0074010 -0.0103817 0.1725755 -0.0021802 0.0575137
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja 0.6013182 0.0125315 0.0106273 0.2194009 -0.0146694 0.0364006 0.0268798 -0.0157811 0.0035517 1.0000000 -0.0039753 0.0166355 0.0736215 0.1062286 -0.0378999 -0.0171189 0.0559764 0.0623044
Vreme_naplate_potrazivanja 0.5968830 0.0152887 -0.0354183 -0.0583805 -0.0089752 0.1176060 -0.4595382 0.0317831 0.2513761 -0.0039753 1.0000000 0.1537135 -0.1261463 -0.0037859 -0.0047127 0.2907848 0.0046339 0.1520589
Rigorozni_racio_redukovane_(monetarne)_likvidnosti 0.5891707 0.4168406 0.3810735 0.1852934 -0.0267447 0.1870060 0.0517380 -0.0514815 -0.0089706 0.0166355 0.1537135 1.0000000 -0.0349812 0.0971327 -0.0877178 0.0745876 0.0245291 0.3011249
Racio_obrta_poslovne_imovine 0.5872213 -0.1516384 -0.0267154 0.3427016 0.0458866 0.0951495 0.0901639 -0.1306944 -0.0478035 0.0736215 -0.1261463 -0.0349812 1.0000000 -0.0113001 -0.0900542 -0.1675202 0.0577446 0.1696654
Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio) 0.5733705 0.0558360 0.1808397 0.3524184 -0.0274399 0.0880883 0.0508694 -0.0442208 -0.0074010 0.1062286 -0.0037859 0.0971327 -0.0113001 1.0000000 -0.0070101 -0.0461001 0.1114824 0.0148283
udeo_u_kapitalu 0.5680543 -0.0844406 -0.0718441 -0.0880921 0.0305530 -0.0747342 0.0523599 0.0891322 -0.0103817 -0.0378999 -0.0047127 -0.0877178 -0.0900542 -0.0070101 1.0000000 0.0771957 -0.0118592 -0.0744592
Vreme_kreditiranja_kupaca 0.5599333 -0.0054643 -0.0419165 -0.1147123 -0.0173417 -0.2800573 -0.2583952 0.0013485 0.1725755 -0.0171189 0.2907848 0.0745876 -0.1675202 -0.0461001 0.0771957 1.0000000 0.0022102 0.1150678
Rast_EBITDA 0.5587844 0.0118250 0.0142587 0.2206145 0.0006459 0.0164206 0.0290077 -0.0565529 -0.0021802 0.0559764 0.0046339 0.0245291 0.0577446 0.1114824 -0.0118592 0.0022102 1.0000000 0.0318944
T21 0.5514432 -0.1011643 0.0995163 0.1758942 0.0528638 0.1993162 -0.1819115 0.0813129 0.0575137 0.0623044 0.1520589 0.3011249 0.1696654 0.0148283 -0.0744592 0.1150678 0.0318944 1.0000000

Da sumiramo, do sada smo kod kontinualnih, pregledali diskriminativnost. Generalno 5 preporucuje da se odradi univariate logisticka pa njena diskriminativnost testira. Medjutim ovde smo pratili 6 gde smo posmatrali diskriminativnost samih varijabli. Dalje, postoji par varijabli koje bismo mogli da transformisemo u kategoricke, sto je pozeljno.

Osim testiranja monotonosti hipoteze, negde se testira i postojanje linearne zavisnost izmedju logaritma empirijskih sansi i varijabli7 i istovremeno se transformisu varijable. 8 prikazuju postupak transformacije ali i upozoravaju na opasnost od data.mining-a, 9 i 10 takodje primenjuju istovetan postupak. Mi cemo ovde koristiti postupak opisan u 11 za par varijabli koje nisu pokazale monotonu zavisnost sa hipotezom, ukoliko nuzda natera, ali samo tada, transformisacemo sve kontinualne varijable. Za sada cemo ovaj postupak primeniti na varijablama Pokriće neto kamata, Asset turnover. Varijabla koju cemo pretvoriti u kategoricku je Udeo u kapitalu banke. Dinamicke varijable Rast EBITDA i Racio obrta poslovne imovine nemaju neku previse znacajnu diskriminativnu moc da bi se opravdalo skracenje citave serije uzorka, tako da ce se tretirati kao da su otpale u univariate analysis usled velikog broja nedostajucih vrednosti. Napravicemo jedan izuzetak kada budemo primenili pravilo odstranjivanja varijabli usled nedostajucih vrednosti, a to je varijabla koja je na granici, Cash_ratio jer je pokazala veliku diskrimacionu moc. Diskriminacionu moc gledamo po znacajnosti intervala poverenja od 95%, koji se kod funkcije u R-u racuna bootstrapovanjem. Generalno, vrednosti AUROC-a u vecim uzorcima koje imaju vrednosti vece od 55 se mogu smatrati znacajnim.

Pa hajde da krenemo sa gore navedenim. Takodje, videh da je mozda broj zaposlenih bilo potrebno rtacunati prema aktivi kao racio, ali to mi ranije nije palo na pamet, mada ne mislim da bi imalo znacajnih promena, eventualno, varijabla koja bi imala smisla je procentualna promena ove varijable, što bi, opet, zahtevalo gubljenje prve godine observacija samo zbog nje, jer se druge dinamicke varijable nisu pokazale kao dovoljno diskriminativno znacajne.

Dodatno o dinamickim varijablama, u buducim vezbama, predlazem da se skroz izbace iz selekcije iz razloga sto nisu monotone, naime, buduci da ove varijable mogu uzimati kako negativne tako i pozitivne vrednosti. Primera radi, moguc je sledeci slucaj, recimo da imamo dva preduzeca \(X^{[1]}\) i \(X^{[2]}\), u roku od dve godine oni su ostvarili sledece vrednosti nekog racija koji je obrnuto povezan sa difoltom (veci racio-manji PD):
\[ t:X_{t}^{[1]}=-0.5, X_{t}^{[2]}=0.7 \\ t+1:X_{t+1}^{[1]}=-0.9, X_{t+1}^{[2]}=0.9 \]
Tako da ukoliko sada izracunamo rast ovog racija za oba preduzeca dobijamo:
\[R_{x^{[1]}}=\frac{X_{t+1}^{[1]}}{X_{t}^{[1]}}-1=80 \%\\ R_{x^{[2]}}=\frac{X_{t+1}^{[2]}}{X_{t}^{[2]}}-1=28\% \]

, sto bi znacilo da preduzece 1 ima bolji PD od preduzeca 2 po pocetnoj hipotezi, a to ne moze biti jer je pozicija preduzeca 1 od starta bila losija i jos se pogorsala u sledecih godinu dana. Ovo je glavni razlog zbog koga, verovatno, ovakve varijable nisu pokazale jaku diskriminativnu moc. Kada se odlucimo u buducnosti za proracun rasta kao potencijalnu varijablu, potrebno je da on pre svega bude racunat na monotonim varijablama, koje ne menjaju znak!

Nastavljamo:

Tretman problematicnih varijabli

Ovako, generalno, ono sto nismo (nismo hteli komentarisati) komentarisali su simetricnosti varijabli. Pozitivno asimetricno je bar pola posmatranih varijabli tako da bi valjala neka vrsta logaritmovane transformacije uz vodjenje racuna o negativnim vrednostima (na primer transformacija tipa: \(\log(var + \min(var) + 1))\) bi se pobrinula za negativne vrednosti. Box Za negativnu asimetricnost bi koristili eventualno eksponencijalnu transformaciju. Videcemo posle prvog stepwisea i AUROC-a.

Ipak, ovde cemo se koncentrisati na par prethodno napomenutih varijabli.

Pokriće neto kamata

Prvo cemo podeliti varijablu na n intervala. Za optimalan broj intervala mozemo iskoristiti drugu funkciju koja ima algoritam koji bira broj intervala od 10 do 20 na osnovu odredjenih kriterijuma, vidi help funkcije dole.

#kreiram tabelu od pokrica neto kamata i indikatora default-a
data<-lrge.training[,c("default.y","Pokrice_neto_kamata")]
IV <- create_infotables(data=data,
                        y="default.y", 
                        parallel=FALSE)
IV_Value = data.frame(IV$Summary)
IV_Value
IV$Tables
$Pokrice_neto_kamata
plot_infotables(IV,"Pokrice_neto_kamata")

Dakle optimum je 10, imajuci u obzir nedostajuce vrednosti kao 11 kategoriju. Sada racunamo fiting funkciju transformacije. Generalno, mogli bismo podeliti varijablu u 8 kategorickih, ali ja bih izbegao to. Hajde prvo da vidimo empirijsku distribuciju, pa da fitujemo.

#izracunam medijanu po svakom binu
#ovo je ujedno i prvi put da koristim listu u R-u
calibrate_parameters=function(tabela, varijabla, default.varijabla, 
                              broj_binova=8, 
                              outlier.quant=c(0.99,0.01)){
  tabela$id<-1:nrow(tabela)
  
  #provera da li je clasa tabele data.table objekat
  if(!is.data.table(tabela)) tabela=as.data.table(tabela)
  
  #mora ovako da bi se u funkciji pozvao naziv kasnije u eval funkciji, bag u data.table koji se ovako prevazilazi
  varijabla=as.name(varijabla)
  default.varijabla=as.name(default.varijabla)
  
  ############################################################################################
  #                              kontinualna transformacija                                  #
  ############################################################################################
    #################################Log odds transformacija##################################
      #kreiram kategoricku varijablu-kolonu u tabeli koja nam govori kojem quantilu, decilu.. (zavisno od broja binova) pripada data observacija varijable
      tabela[,varijabla_Bin:=quantcut(
        tabela[,eval(varijabla)],
        q = seq(0,1,by = 1/broj_binova)
        )
        ]
      
      #kreiram tabelu medijana sa odgovarajucim pdjevima
      temp_data<-na.omit(
        tabela[,.(prob=sum(eval(default.varijabla))/(.N),
                  medians = median(eval(varijabla))),
               by = varijabla_Bin]
        )[order(medians)]
      
    
      #fitujem funkciju na medijane prema pdjevima
      loes_fit<-loess(prob~medians,data=temp_data )
      y<-tabela[,eval(varijabla)]
      
      #sredjujem autljere pre forecasta
      ubound<-quantile(x = y, probs = outlier.quant[1],na.rm = T)
      lbound<-quantile(x = y, probs = outlier.quant[2],na.rm = T)
      
        #sredi te autlajere bre
      y[y>ubound]<-ubound
      y[y<lbound]<-lbound
    
      #forkastujem komplet vrednosti varijable shodno dobijenim vrednostima fit funkcije
      
      median.H<-tabela[eval(default.varijabla)==0,median(eval(varijabla),na.rm = T)]
      median.D<-tabela[eval(default.varijabla)==1,median(eval(varijabla),na.rm = T)]
      
      y[is.na(y) & tabela[,eval(default.varijabla)]==1]<-median.D
      y[is.na(y) & tabela[,eval(default.varijabla)]==0]<-median.H
        
      p<-predict(loes_fit,y)
    
      #p[p<0]=0.000001 #za svaki slucaj
      # p[p>1]=0.999999
      #trebaju mi log odds a ne pdjevi
  
      tabela[,transformisana_varijabla:=log(p/(1-p))]
    
    ##########################################BOX COX transformacija######################### 
      
      # to find optimal lambda
      vector<-tabela[,eval(varijabla)]
      lambda = BoxCox.lambda( vector )
      # now to transform vector
      Box.cox.varijabla = BoxCox( vector, lambda)
      tabela[,Box.cox.varijabla:=Box.cox.varijabla]
      
  
  ############################################################################################
  #                              binovi                                                      #
  ############################################################################################
  
    ##############################log odds binovi#############################################
    
    #racunam pdjeve za svaki bin i dodeljujem ih pored stare vrednosti varijable
        #NA pretvaram u character da bih sracunao i za njega DF
   
      tabela[,varijabla_Bin_numeric:=as.numeric(varijabla_Bin)][
        ,varijabla_Bin_numeric:=as.character(varijabla_Bin_numeric)][
          is.na(varijabla_Bin_numeric),varijabla_Bin_numeric:="NA"]
      
      tabela[,prob:=sum(eval(default.varijabla))/(.N),by = varijabla_Bin_numeric]
      
        #record a plot
      p1=ggplot(data=tabela, aes(varijabla_Bin_numeric))+geom_bar(aes(weight=eval(default.varijabla)))
      
      #ali trebaju mi log odds naravno
      tabela[,odds:=(prob/(1-prob))]
  
    ###################################woe binovi###############################################
  
      data<-data.frame(
        default.varijabla=tabela[,eval(default.varijabla)],
        continualna_varijabla=tabela[,eval(varijabla)])
    
      WOE = create_infotables(data = as.data.frame(data),
                      y="default.varijabla", 
                      parallel=FALSE,
                      bins = broj_binova)
      
      woe =WOE$Tables$continualna_varijabla[,c(1,4)]
     
      #ako postoje missing values 
      if(woe[1,1]=="NA"){
       woe$"varijabla_Bin_numeric"=c("NA",1:broj_binova) 
      } else {
        woe$"varijabla_Bin_numeric"=as.character(1:broj_binova)
      }
       
      woe.plot<-plot_infotables(WOE,"continualna_varijabla")
    
      #prebaci kategorije u brojeve pa njih u character zbog na iz prethodne tabele, pa na u character jos jednom da bi mogao da ga vlookapuje
      
      
    
      tabela<-merge(x=tabela,y=woe, all.x = T)[order(id)][,id:=NULL]#varijabla_Bin_numeric je trazena varujabla
  
  
  
  ################################################################################################
  #                            AUC vrednosti                                                     #
  ################################################################################################
      
    #racunam auc vrednost, staru pa novu  noooovu 
    #stara
  auroc.s<-auc(
      as.numeric(tabela[,eval(default.varijabla)]),
      as.numeric(tabela[,eval(varijabla)]))
    auc.vrednost.pre<-as.numeric(auroc.s)
    #nova
  auroc.n<-auc(
      as.numeric(tabela[,eval(default.varijabla)]),
      as.numeric(tabela[,transformisana_varijabla]))
  auc.vrednost.posle<-as.numeric(auroc.n)
  ###############################################################################################
  #                            Ostali Grafici                                                   #
  ###############################################################################################
  
  col.num.default<-grep("default", colnames(tabela))
  col.num.varijabla<-which(colnames(tabela)==varijabla)
  
  ostali_plotovi_pre=ploting(tabela,col.num.varijabla,col.num.default)
    
  col.num.default<-grep("default", colnames(tabela))
  col.num.varijabla<-which(colnames(tabela)=="transformisana_varijabla")
  ostali_plotovi_posle=ploting(tabela,col.num.varijabla,col.num.default)
  
  col.num.varijabla<-which(colnames(tabela)=="Box.cox.varijabla")
  box.cox_plotovi<-ploting(tabela, col.num.varijabla, col.num.default)
  
  output<-list()
  output = list(monotonicity_graph = p1,
                ostali_plotovi_pre=ostali_plotovi_pre,
                ostali_plotovi_posle=ostali_plotovi_posle,
                woe.plot=woe.plot,
                auc.vrednost=data.frame(auc.vrednost.pre,auc.vrednost.posle),
                fit_funkcija_objekat = loes_fit)
  
  tabela$transformisana_varijabla->output[[7]]
  names(output)[7]<-paste(varijabla,".tr",sep = "")
  
  tabela$odds->output[[8]]
  names(output)[8]<-paste(varijabla,".odds",sep = "")
  
  tabela$WOE->output[[9]]
  names(output)[9]<-paste(varijabla,".WOE",sep = "")
  
  Box.cox.varijabla->output[[10]]
  names(output)[10]<-paste(varijabla,".Box.Cox",sep = "")
  
  box.cox_plotovi->output[[11]]
  names(output)[11]<-paste(varijabla,".Box.Cox.plot",sep = "")
  
  output
}
Pokrice_neto_kamatar=calibrate_parameters(lrge.training, broj_binova=8,
                                         "Pokrice_neto_kamata",
                                         "default.y",
                                         outlier.quant=c(0.95,0.05)
                                         )
NaNs producedIgnoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 108 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!
Pokrice_neto_kamatar$monotonicity_graph

Pokrice_neto_kamatar$ostali_plotovi_posle

Asset turnover

Asset_turnover=calibrate_parameters(lrge.training,"Asset_turnover","default.y")
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 110 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!
Asset_turnover$ostali_plotovi_posle

Asset_turnover$monotonicity_graph

Kategoricke promenljive:

Postoje tri kategoricke varijable koje je potrebno analizirati:

rpivotTable(lrge.training.kategoricke,
            rows = "default.y", 
            cols = "Strani_investitor",
            aggregatorName = "Count as Fraction of Columns")

Sifra sektora:

freq_table=function(dta,kategorical,default){
  kategorical=as.name(kategorical)
  default=as.name(default)
  tmp=dta[,.N,by=.(eval(kategorical),eval(default))]
  frekvenca_sektor<-dcast(tmp,eval(kategorical)~eval(default),value.var="N")
  frekvenca_sektor$`0`[is.na(frekvenca_sektor$`0`)]=0
  frekvenca_sektor$`1`[is.na(frekvenca_sektor$`1`)]=0
  ukupno<-frekvenca_sektor$`0`+frekvenca_sektor$`1`
  frekvenca_sektor<-cbind.data.frame(frekvenca_sektor,ukupno)
  frekvenca_sektor[,default_rate:=frekvenca_sektor$`1`/ukupno]
  as.data.frame(frekvenca_sektor)
}
freq_table(lrge.training.kategoricke,"Sifra_sektor","default.y")

Posmatrajuci tabelu vidimo da vec navedene kriterijume zadovoljavaju C, F, G sektor, tako da ostale mozemo svrstati u poseban sektor. Medjutim, ono sto uvidjamo je, nazalost, da sva tri sektora imaju slicnu stopu difolta kao i komplet uzorak, zakljucujemo da nam je ova varijabla beskorisna..osim F, gradjevinarstvo, koje mozemo tretirati kao pojedinacnu varijablu.

lrge.training.kategoricke$Sifra_sektor[lrge.training.kategoricke$Sifra_sektor!="F"]<-"Z"
lrge.test.kategoricke$Sifra_sektor[lrge.test.kategoricke$Sifra_sektor!="F"]<-"Z"
freq_table(lrge.training.kategoricke,"Sifra_sektor","default.y")
data_sifra_sektor<-lrge.training.kategoricke[,c("default.y","Sifra_sektor")]
IV_sifra_sektor<-create_infotables(data=data_sifra_sektor,
                        y="default.y", 
                        parallel=FALSE)
IV_sifra_sektor$Tables
$Sifra_sektor
NA

Information value od 0.04 deluje kao prihvatljiv, ali ovde imamo samo 19 difoltera na jednu varijablu ciji bin ne ulazi

Sifra opstine:

U cilju iskorišćenja ove varijable posegnuli smo za podelom jedinica Lokalne samouprave po ekonomskoj razvijenosti, kao i na drugu podelu gde su Beograd, Novi SAd i Nis u jednoj kategoriji kao najveci gradovi, a ostali gradovi u ostalim kategorijama, na kraju mozemo i izdvojiti samo Beograd. Pregledajmo prvo kakvo je stanje po ostinama:

freq_table(lrge.training.kategoricke,"Sifra_opstine","default.y")

Uvidjamo da Beograd (najverovatnije) i Novi Sad jedini imaju preko 100 duznika, tako da ima smisla deliti na Beograd, Novi Sad i ostale opstine. Medjutim, vidimo da je default rate u Beogradu oko 10% sto je ,opet, blizu default ratea uzorka, samim tim, i Beograd otpada, ali bi eventualno mogli koristiti Novi Sad kao posebnu kategoriju. Pokusacemo da uvidimo da li nam predlozena varijabla o razvijenosti opstina donosi nesto novo (izvrsena je mala korekcija kod Zvecanj-a gde je dodata 4 kategorija ekonomske razvijenosti buduci da je opstina sa Kosova):

#ucitavam pripremljenu tabelu sa kategorijama razvijenosti
opstine_razvijenost <- read_delim("C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 5/opstine_razvijenost.csv", 
";", escape_double = FALSE, trim_ws = TRUE)
Parsed with column specification:
cols(
  Total = col_integer(),
  Razvijenost = col_character(),
  Sifra_opstine = col_integer()
)
#opstine_razvijenost$Sifra_opstine<-factor(opstine_razvijenost$Sifra_opstine)
#jbg moramo voditi racuna o redosledu ovde!!!!!!
lrge.training.kategoricke$id  <- 1:nrow(lrge.training.kategoricke)
lrge.test.kategoricke$id  <- 1:nrow(lrge.test.kategoricke)
lrge.training.kategoricke<-merge(lrge.training.kategoricke,opstine_razvijenost,all.x = T)
lrge.test.kategoricke<-merge(lrge.test.kategoricke,opstine_razvijenost,all.x = T)
lrge.training.kategoricke<-lrge.training.kategoricke[order(lrge.training.kategoricke$id), ][,id:=NULL]
lrge.test.kategoricke<-lrge.test.kategoricke[order(lrge.test.kategoricke$id), ][,id:=NULL]
freq_table(lrge.training.kategoricke,"Razvijenost","default.y")

Ima logike svrstati cetvrtu i trecu kolonu u jednu, mada time podizemo default rate na 16% sa 12%, treba imati u obzir da je u ovu kolonu uslo i preduzece koje je sa Kosova koje je ranije bilo svrstano u ovu kategoriju, a koje je difoltiralo. Time bi broj observacija u klasi 3 bio \(99\approx100\). Koriscenje WOE i IV u slucaju velikih preduzeca, generalno, nije izvodljivo, usled malog broja difoltera po klasi faktorske varijable (12 predlaze bar 50 difoltera po kategoriji klasifikacije), ipak pogledacemo ova dva statistika kao putokaz i imati u vidu predlog 13 gde navodi za IV statistik sledece:

  • Ukoliko je manji od 0.02, nije nam od preke vaznosti
  • Ukoliko je izmedju 0.02 i 0.1 onda postoji slaba diskriminacija i veza sa racijom sansi
  • Ukoliko je izmedju 0.1 i 0.3 onda postoji srednje jaka veya sa racijom sansi i
  • Preko 0.3 oynacava sjajnu poveyanost sa diskriminacijom i racijom sansi (Srpski za Good/Bad odds ratio)

Spojili smo 4 i 3 kategoriju

#kreiram novu varijablu gde 4 pripajam 3jci
lrge.training.kategoricke$Razvijenost[lrge.training.kategoricke$Razvijenost==4]<-3
lrge.test.kategoricke$Razvijenost[lrge.test.kategoricke$Razvijenost==4]<-3
freq_table(lrge.training.kategoricke,"Razvijenost","default.y")
data_opstine_po_razvijenosti<-lrge.training.kategoricke[,c("default.y","Razvijenost")]
IV_opstine_po_razvijenosti<-create_infotables(data=data_opstine_po_razvijenosti,
                        y="default.y", 
                        parallel=FALSE)
IV_opstine_po_razvijenosti$Tables
$Razvijenost
NA

Dobili smo IV oko 0.07 sto zadovoljava medjutim jako je mali broj difolta u kategoriji 3 imajuci u vidu broj opstina koje spadaju u nju, spajamo 2 i 3

#kreiram novu varijablu gde 3 i 2 spajam
lrge.training.kategoricke$Razvijenost[lrge.training.kategoricke$Razvijenost==3]<-2
lrge.test.kategoricke$Razvijenost[lrge.test.kategoricke$Razvijenost==3]<-2
freq_table(lrge.training.kategoricke,"Razvijenost","default.y")
data_opstine_po_razvijenosti<-lrge.training.kategoricke[,c("default.y","Razvijenost")]
IV_opstine_po_razvijenosti<-create_infotables(data=data_opstine_po_razvijenosti,
                        y="default.y", 
                        parallel=FALSE)
IV_opstine_po_razvijenosti$Summary

Oko 0.04 sto bi moglo da nam znaci nesto

Pokusajmo sada sa Novim Sadom:

lrge.training.kategoricke$Sifra_opstine[lrge.training.kategoricke$Sifra_opstine!="89010"]<-"0000"
lrge.test.kategoricke$Sifra_opstine[lrge.test.kategoricke$Sifra_opstine!="89010"]<-"0000"
freq_table(lrge.training.kategoricke,"Sifra_opstine","default.y")
data_2opstine<-lrge.training.kategoricke[,c("default.y","Sifra_opstine")]
IV_2opstine<-create_infotables(data=data_2opstine,
                        y="default.y", 
                        parallel=FALSE)
IV_2opstine$Summary

Ipak cemo ici sa opstinama po razvijenosti

Strani investitor

Pogledajmo prvo frekvencionu tabelu

freq_table(lrge.training.kategoricke,"Strani_investitor","default.y")

Postoji ocigledna razlika, imajuci u vidu da ovde imamo samo dve varijable, to je i ocekivano, hajde da vidimo IV:

IV_strani_investitor$Tables
$Strani_investitor
NA

Imamo IV oko 0.03. Uzecemo ovako.

Evaluacija regresije

Dosadasnji rezultati:

Otpadanje usled NA vrednosti, prezivele su sledece varijable:

summary_table<-as.data.frame(summary_table)
preziveli.NA<-rownames(summary_table[summary_table$NAspercent<10,])
knitr::kable(preziveli.NA)
The table should have a header (column names)
Broj_zaposlenih
Velicina
Rigorozni_racio_redukovane_(monetarne)_likvidnosti
Racio_novcane_likvidnosti_(Cash_ratio)
Opsti_racio_likvidnosti
Stepen_zaduzenosti
Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)
Racio_pokrica_obrtne_imovine
Gotovinski_ciklus_1
Vreme_vezivanja_zaliha
Vreme_kreditiranja_kupaca
Vreme_naplate_potrazivanja
Vreme_placanja_dobavljacima
Asset_turnover
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja
Basic_Earnings_Power_Ratio
Pokrice_neto_kamata
Cena_tudjih_izvora_sredstava
T11
T12
T13
T14
T15
T21
Altman I
Altman emerging markets
Altman private firms
udeo_u_kapitalu

Ciscenje usled korelacija i AUROC-a manjeg od 0.55

preziveli.corr.AUC<-row.names(clean_cor)

Presek ova dva nastavlja u multivariate.

#odabrani<-c("Racio_novcane_likvidnosti_(Cash_ratio)",intersect(preziveli.NA,preziveli.corr.AUC))
odabrani<-intersect(preziveli.NA,preziveli.corr.AUC)

Ovde podsecamo da cemo ipak dodati kash racio u grupu. Nismo proveravali ovde redove ali bi trebalo kada budemo radila sa malim i srednjim preduzecima. Sredimo sada NA vrednosti:

Funkcija za nedostajuce i ekstreme:

replace_outlier_with_quantile <-
  function(x,
  quant = TRUE,
  probs = c(0.01, 0.99),
  na.rm = TRUE) {
  if (quant == T) {
  qnt <- quantile(x, probs = probs, na.rm = na.rm)  # get %iles
  U <- qnt[2]
  L <- qnt[1]
  y <- x
  y[x < L] <- L  # replace values below lower bounds
  y[x > U] <- U
  y
  } else if (quant == F) {
  qnt <- quantile(x, probs = c(.25, .75), na.rm = na.rm)  # get %iles
  H <- 3 * IQR(x, na.rm = na.rm)  # outlier limit threshold
  y <- x
  y[x < (qnt[1] - H)] <-
  (qnt[1] - H)  # replace values below lower bounds
  y[x > (qnt[2] + H)] <-
  (qnt[2] + H)  # replace values above higher bound
  y  # returns treated variable
  } 
  
  }
  
  
  replace_missing_with_median <-
  function(x,
  default.colona = as.name(default.y),
  probs = c(0.01, 0.99),
  na.rm = TRUE,
  training = T,
  ...) {
  x < as.data.frame(x)
  median. <-
  median(x, na.rm = na.rm)
  median.h = median(x[default.colona == 0], na.rm = na.rm)
  median.d = median(x[default.colona == 1], na.rm = na.rm)
  
  if (training == T) {
  x[is.na(x) & default.colona == 0] <- median.h
  x[is.na(x) &
  default.colona == 1] <-
  median.d
  } else {
  x[is.na(x)] <- median.
  }
  x
  }
  
  
  
  
  replace_outlier_with_na <- function(x,quant = TRUE,
  probs = c(0.01, 0.99),
  na.rm = TRUE) {
  if (quant == T) {
  qnt <- quantile(x, probs = probs, na.rm = na.rm)  # get %iles
  U <- qnt[2]
  L <- qnt[1]
  y <- x
  y[x < L] <- NA  # replace values below lower bounds
  y[x > U] <- NA
  y
  } else if (quant == F) {
  qnt <- quantile(x, probs = c(.25, .75), na.rm = na.rm)  # get %iles
  H <- 3 * IQR(x, na.rm = na.rm)  # outlier limit threshold
  y <- NA
  y[x < (qnt[1] - H)] <- NA  # replace values below lower bounds
  y[x > (qnt[2] + H)] <- NA  # replace values above higher bound
  y  # returns treated variable
  
  }
  }
  
 
  
  
  replace_missing_with_knn <- function(x, response_name = "default.y", training = T) {
    
    x <- as.data.frame(x)
    response<-x[,eval(response_name)]
    if (training == F) {
      if (anyNA(x)) {
        x[,!names(x) %in% response_name] <-
          knnImputation(x[,!names(x) %in% response_name])  # missing value treatment
        }
    } else {
      if(anyNA(x)) {
        x[response==1,!names(x) %in% response_name] <-
          knnImputation(x[response==1,!names(x) %in% response_name])  # missing treatment
        }
        
      if (anyNA(x)) {
        x[response==0,!names(x) %in% response_name] <-
          knnImputation(x[response==0,!names(x) %in% response_name])  # missing value treatment  
        
        }
      
    }
    as.data.table(x)
    }
    
#inputData_cont <- as.data.frame (sapply(clean_b[,9:34], replace_outlier_with_missing))  # this will make outliers as NA 
#summary_table2<-sapply(inputData_cont,my.summary,arg=T)

Kreiramo zavrsni uzorak:
______________________

Tretman nedostajucih i tretman autlajera, potom dodajemo kategoricke

finalni_lrge<-lrge.training[,c(odabrani), with=F]
#finalni_lrge<-cbind.data.frame(finalni_lrge,Asset_turnover$Asset_turnover.tr,Pokrice_neto_kamata$Pokrice_neto_kamata.tr)
#finalni_lrge<-as.data.table(sapply(finalni_lrge,replace_outlier_with_quantile))
finalni_lrge<-as.data.table(sapply(finalni_lrge,replace_outlier_with_na))
finalni_lrge$default.y<-lrge.training$default.y
finalni_lrge<-replace_missing_with_knn(finalni_lrge)
finalni_lrge$default.y<-NULL
############################################################################
#                               opciono                                    #
#                                                                          #
############################################################################
AA<-data.frame(1:1255);n=1                                                 #
finalni_lrge$default.y <- default.y                                        #
for(i in names(finalni_lrge)["default.y" != names(finalni_lrge)]) {
  
  n = n + 1
  tmp <- calibrate_parameters(finalni_lrge, i, "default.y")
  AA <- cbind.data.frame(AA, tmp[[7]])
  names(AA)[n] <- names(finalni_lrge)[n]
}


finalni_lrge <- AA
remove(AA)
finalni_lrge[, 1] <- NULL
                                                                          #
                                                                          #
finalni_lrge$default.y <- default.y                                       #
finalni_lrge <- as.data.table(finalni_lrge)                               #
###########################################################################
#spajamo sa kategorickim i skidamo par viskova kategorickih, velicina, total
finalni_lrge <-
  cbind.data.frame(finalni_lrge, lrge.training.kategoricke)[, c("Velicina", "Total", "Sifra_sektor","Sifra_opstine") :=
  NULL]
  
#pretvaram kategoricke u faktor da bi ih glm posmatrao kao kategoricke
finalni_lrge$Razvijenost <- as.factor(finalni_lrge$Razvijenost)
finalni_lrge$Strani_investitor <-
as.factor(finalni_lrge$Strani_investitor)

Dugo ocekivani trenutak:

model.null = glm(default.y ~ 1,
                 data=finalni_lrge,
                 family = binomial(link="logit")
                 )
model.full = glm(default.y ~ .,
                 data=finalni_lrge,
                 family = binomial(link="logit")
                 )
    
step(model.null,
     scope = list(upper=model.full,lower=model.null),
             direction="forward",
             
             data=finalni_lrge,trace=0)

Call:  glm(formula = default.y ~ Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + 
    `Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti + 
    Gotovinski_ciklus_1 + Cena_tudjih_izvora_sredstava + Razvijenost + 
    T21 + Racio_pokrica_obrtne_imovine, family = binomial(link = "logit"), 
    data = finalni_lrge)

Coefficients:
                                      (Intercept)  
                                        -4.810710  
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja  
                                        -0.042006  
         `Racio_novcane_likvidnosti_(Cash_ratio)`  
                                        -4.216509  
                               Stepen_zaduzenosti  
                                         0.031723  
                              Gotovinski_ciklus_1  
                                        -0.001379  
                     Cena_tudjih_izvora_sredstava  
                                         0.023292  
                                     Razvijenost2  
                                         0.289870  
                                     Razvijenost3  
                                         0.977524  
                                              T21  
                                         1.389687  
                     Racio_pokrica_obrtne_imovine  
                                        -0.091868  

Degrees of Freedom: 1254 Total (i.e. Null);  1245 Residual
Null Deviance:      818.2 
Residual Deviance: 719.4    AIC: 739.4
model1 <- glm(formula =default.y~`Racio_novcane_likvidnosti_(Cash_ratio)`+Stepen_zaduzenosti+Gotovinski_ciklus_1+Vreme_naplate_potrazivanja+Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja+Cena_tudjih_izvora_sredstava, family = binomial(link = "logit"), 
    data = finalni_lrge)
model1.data.frame<-data.frame(fit1=model1$fitted.values, dif1=model1$model$default.y)
step(model.full,
     scope = list(lower=model.full,upper=model.null),
             direction="backward",
             data=finalni_lrge, trace=0)

Call:  glm(formula = default.y ~ `Rigorozni_racio_redukovane_(monetarne)_likvidnosti` + 
    `Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti + 
    `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca + 
    Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima + 
    Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + 
    Cena_tudjih_izvora_sredstava + T14 + T21 + udeo_u_kapitalu + 
    Strani_investitor + Razvijenost, family = binomial(link = "logit"), 
    data = finalni_lrge)

Coefficients:
                                                                 (Intercept)  
                                                                  -4.668e+00  
                        `Rigorozni_racio_redukovane_(monetarne)_likvidnosti`  
                                                                  -2.929e-02  
                                    `Racio_novcane_likvidnosti_(Cash_ratio)`  
                                                                  -3.963e+00  
                                                          Stepen_zaduzenosti  
                                                                   3.233e-02  
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)`  
                                                                  -8.045e-07  
                                                Racio_pokrica_obrtne_imovine  
                                                                  -8.617e-02  
                                                         Gotovinski_ciklus_1  
                                                                  -1.470e-03  
                                                   Vreme_kreditiranja_kupaca  
                                                                  -1.278e-03  
                                                  Vreme_naplate_potrazivanja  
                                                                   1.274e-03  
                                                 Vreme_placanja_dobavljacima  
                                                                  -1.462e-04  
                         Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja  
                                                                  -3.180e-04  
                           Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja  
                                                                  -4.009e-02  
                                                Cena_tudjih_izvora_sredstava  
                                                                   2.248e-02  
                                                                         T14  
                                                                   6.987e-04  
                                                                         T21  
                                                                   1.333e+00  
                                                             udeo_u_kapitalu  
                                                                   2.525e-04  
                                                          Strani_investitor1  
                                                                  -1.159e-01  
                                                                Razvijenost2  
                                                                   3.003e-01  
                                                                Razvijenost3  
                                                                   9.554e-01  

Degrees of Freedom: 1254 Total (i.e. Null);  1236 Residual
Null Deviance:      818.2 
Residual Deviance: 717.2    AIC: 755.2
 model2<-  glm(formula = default.y ~ `Rigorozni_racio_redukovane_(monetarne)_likvidnosti` + 
    `Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti + 
    `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca + 
    Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima + 
    Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + 
    Cena_tudjih_izvora_sredstava + T14 + T21 + udeo_u_kapitalu + 
    Strani_investitor + Razvijenost, family = binomial(link = "logit"), 
    data = finalni_lrge)
model2.data.frame=data.frame(fit2=model2$fitted.values, dif2=model2$model$default.y)

Wald statistik:

library(car)
package 㤼㸱car㤼㸲 was built under R version 3.3.3
Attaching package: 㤼㸱car㤼㸲

The following object is masked from 㤼㸱package:gtools㤼㸲:

    logit
Anova(model1, type="II", test="Wald")
Analysis of Deviance Table (Type II tests)

Response: default.y
                                                  Df   Chisq Pr(>Chisq)    
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja  1 12.7734  0.0003516 ***
`Racio_novcane_likvidnosti_(Cash_ratio)`           1  9.0301  0.0026556 ** 
Stepen_zaduzenosti                                 1  8.3352  0.0038883 ** 
Gotovinski_ciklus_1                                1  3.8995  0.0483006 *  
Cena_tudjih_izvora_sredstava                       1  8.6873  0.0032043 ** 
Razvijenost                                        2 10.4438  0.0053972 ** 
T21                                                1  6.2816  0.0121997 *  
Racio_pokrica_obrtne_imovine                       1  2.6143  0.1059071    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Langrange multiplier test:

anova(model2,
      model.null,
      test="Chisq")
Analysis of Deviance Table

Model 1: default.y ~ `Rigorozni_racio_redukovane_(monetarne)_likvidnosti` + 
    `Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti + 
    `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca + 
    Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima + 
    Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + 
    Cena_tudjih_izvora_sredstava + T14 + T21 + udeo_u_kapitalu + 
    Strani_investitor + Razvijenost
Model 2: default.y ~ 1
  Resid. Df Resid. Dev  Df Deviance  Pr(>Chi)    
1      1236     717.15                           
2      1254     818.15 -18     -101 1.452e-13 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Drugi nacin

  auroc.1<-auc(
      as.numeric(model1.data.frame$dif1),
      as.numeric(model1.data.frame$fit1))
 auroc.2<-auc(
      as.numeric(model2.data.frame$dif2),
      as.numeric(model2.data.frame$fit2))
c(auroc.1,auroc.2)
[1] 0.7600067 0.7684494

validacioni uzorak

106264 96946

finalni_lrge.test<-lrge.test[,c(odabrani), with=F]
#finalni_lrge<-cbind.data.frame(finalni_lrge,Asset_turnover$Asset_turnover.tr,Pokrice_neto_kamata$Pokrice_neto_kamata.tr)
finalni_lrge.test<-as.data.table(sapply(finalni_lrge.test,replace_outlier_with_na))
finalni_lrge.test$default.y<-lrge.test$default.y
finalni_lrge.test<-replace_missing_with_knn(finalni_lrge.test,training = F)
finalni_lrge.test$default.y<-NULL
finalni_lrge.test <-
  cbind.data.frame(finalni_lrge.test, lrge.test.kategoricke)[, c("Velicina", "Total", "Sifra_sektor","Sifra_opstine") :=
  NULL]
  
#pretvaram kategoricke u faktor da bi ih glm posmatrao kao kategoricke
finalni_lrge.test$Razvijenost <- as.factor(finalni_lrge.test$Razvijenost)
finalni_lrge.test$Strani_investitor <-
as.factor(finalni_lrge.test$Strani_investitor)
model1.pred<-as.numeric(predict(model1, newdata = finalni_lrge.test, type = "response"))
model2.pred<-as.numeric(predict(model2, newdata = finalni_lrge.test, type = "response"))
dif<-as.numeric(finalni_lrge.test$default.y)
auroc.1.pred<-auc( dif,model1.pred)
auroc.2.pred<-auc( dif,model2.pred)
c(auroc.1.pred,auroc.2.pred)
[1] 0.7541885 0.7445262

Konacno biramo ovu formulu:

glm(formula =default.y~Racio_novcane_likvidnosti_(Cash_ratio)+Stepen_zaduzenosti+Gotovinski_ciklus_1+Vreme_naplate_potrazivanja+Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja+Cena_tudjih_izvora_sredstava, family = binomial(link = “logit”), data = finalni_lrge)`
______________________________________


  1. Ovde se to ne vidi jer je u medjuvremenu prepravljeno, vidi razvojni folder, korake 2,3,5. Osim vecih vrednosti koje su se javile doslo se do saznanja da velicina pravnih lica u APR bazi nije bila preracunata po kriterijumima novog zakona, vidi Zakon o racunovodstvu Sl. glasnik RS br. 622013 pa je ona naknadno preracunata u excelima posle cega je ovaj skript ponovo pokrenut tako da se ovaj tekst koji si procitao odnosio na raniju verziju…,Inception.

  2. Videcemo kasnije da ovaj kriterijum zavisi i od iskustva samog autora, tako na primer OeNB i FMA (2004) preporucuju brisanje ukoliko nedostaje vise od 20% vrednosti dok smo ovde naveli izvor koji preporucuje brisanje varijable ukoliko nedostaje 10% vrednosti.

  3. Vidi Rating Models and Validation - Oesterreichische Nationalbank (OeNB).

  4. Hayden, E., & Porath, D. (2011). Statistical Methods to Develop Rating Models. In B. Engelmann, and R. Rauhmeier (Eds.), The Basel II Risk Parameters: Estimation, Validation, Stress Testing – with Applications to Loan Risk Management (pp. 1–12). New York: Springer.

  5. Hayden, E., & Porath, D. (2011). Statistical Methods to Develop Rating Models. In B. Engelmann, and R. Rauhmeier (Eds.), The Basel II Risk Parameters: Estimation, Validation, Stress Testing – with Applications to Loan Risk Management (pp. 1–12). New York: Springer.

  6. Developing, Validating and Using Internal Ratings - De Laurentis

  7. Hayden, E., & Porath, D. (2011). Statistical Methods to Develop Rating Models. In B. Engelmann, and R. Rauhmeier (Eds.), The Basel II Risk Parameters: Estimation, Validation, Stress Testing – with Applications to Loan Risk Management (pp. 1–12). New York: Springer.

  8. Credit Risk Modeling using Excel and VBA, 2nd Edition - Gunter Löeffler, Peter N. Posch.

  9. Developing, Validating and Using Internal Ratings - De Laurentis

  10. Hayden, E., & Porath, D. (2011). Statistical Methods to Develop Rating Models. In B. Engelmann, and R. Rauhmeier (Eds.), The Basel II Risk Parameters: Estimation, Validation, Stress Testing – with Applications to Loan Risk Management (pp. 1–12). New York: Springer.

  11. Credit Risk Modeling using Excel and VBA, 2nd Edition - Gunter Löeffler, Peter N. Posch.

  12. The Basel II Risk Parameters: Estimation, Validation, Stress Testing – with Applications to Loan Risk Management, Chapter 3. New York: Springer.

  13. Credit Risk Scorecards: Developing and Implementing Intelligent Credit Scoring, by Naeem Siddiqi

LS0tDQp0aXRsZTogIlNrdXBsamFuamUgcG9kYXRha2EgemEgRVctTkJTIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHllcw0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KPGJvZHkgc3R5bGU9ImZvbnQtZmFtaWx5OnRpbWVzO3RleHQtYWxpZ246anVzdGlmeSIgPg0KIyMgMS4gVWNpdGF2YW5qZSBwb2RhdGFrYSBBUFItYSAgDQoNClVjaXRhY2VtbyBkdmEgY3N2IGZhamxhLCBqZWRhbiBzYWRyemkgc3RhcmlqZSBkYXR1bWUgZG8gMjAxMy4gZ29kaW5lIGRvayBkcnVnaSBzYWRyemkgbm92aWplIGRhdHVtZSBvZCAyMDE0LiBnb2RpbmUgcGEgbmEgZGFsamUuIFV2ZXppdmFuamUgQU9QLWEgcG8gbm92b20gaSBzdGFyb20ga29udG5vbSBva3ZpcnUgamUgdmVjIHVyYWRqZW5vIGkgc2FjdXZhbm8gdSBkYXRhIGR2YSBjc3YgZmFqbGEuIFNhbWkgZmFqbG92aSBuZSBzYWRyemUgQU9QLWUhISEgUmF6bG9nIGplIMWhdG8gbmUgYmkgbW9nbGkgZGEgc2Ugc3BvamUgdSBqZWRhbiBmYWpsIGJ1ZHXEh2kgZGEgQU9QLWkgIHBvIHN0YXJvbSBpIG5vdm9tIGtvbnRub20gb2t2aXJ1IG5pc3UgbWFwaXJhbmkgamVkYW5hIG5hIGplZGFuIGkgc2FtaW0gdGltIG5lIGJpIG1vZ2xpIGRhIHNlICJuYWxlcGUiIGplZGFuIG5hIGRydWdpIHUgY2lsanUgZG9iaWphbmphIGplZG5vZyBgZGF0YS5mcmFtZWAtYSBqZXIgYmkgaW1hbGkgcmF6bGljaXQgYnJvaiBBT1AtYSAoY2l0YWoga29sb25hKSwgZmFqbG92aSBtZWRqdXRpbSBzYWRyemUgcHJvcmFjdW5hdGEgZmluYW5zaWpza2EgcmFjaWphLiBGYWpsb3ZpIHNhZHJ6ZSBmaW5hbnNpanNrYSByYWNpamEga29qYSBzdSBzcmFjdW5hdGEgaXogcHJlbWFwaXJhbmloIGl6IEFPUC1hIGR2YSBrb250bmEgb2t2aXJhIChub3ZpIGkgc3Rhcmkga29udG5pIG9rdmlyKS4gWmEgZGV0YWxqbmlqaSBwcmVnbGVkLCB1dmlkIHUgcG9qZWRpbmFjbmUgQU9QLWUgcG9nbGVkYXRpIGZhamxvdmUgaXogZm9sZGVyYSBvdmUgYW5hbGl6ZSwgZmFqbG92aSBjZSBzZSBuYWxheml0aSB1IDxmb250IGNvbG9yPSJyZWQiPiJ+XFxFYXJseSB3YXJuaW5nXFxCb3R0b20gVXBcXEtvcmFrIDNcXFBva2F6YXRlbGppIjwvZm9udD4gZ2RlICB+IHByZWRzdGF2bGphIGFkcmVzdSBuYSBrb2pvaiBqZSBwb3N0YXZsamVuIGZvbGRlci4gIA0KRG9kYXRubyBwb2phc25qZW5qZSBvIHRvbGlrbyBzcG9taW5qYW5pbSBBT1AtaW1hOg0KDQo8cCBzdHlsZT0ibWFyZ2luLWxlZnQ6IDQwcHg7bWFyZ2luLXJpZ2h0OiA0MHB4O3RleHQtYWxpZ246anVzdGlmeTtjb2xvcjpncmF5Ij4NClUgQVBSIGJhemkgc3Ugc3ZlIHBvemljaWplIGl6IGJpbGFuc2Egc3RhbmphLCBiaWxhbnNhIHVzcGVoYSwgdG9rb3ZhIGdvdG92aW5lLCBzdGF0aXN0aWNraWggcG9kYXRha2EgbyBwcmVkdXplY3UgKHN0YXRpc3RpY2tpIGFuZWtzKSB0cmV0aXJhbmUga2FvIEFPUCBwb3ppY2lqZSwgdGFrbyBuYSBwcmltZXIgYnJvaiB6YXBvc2xlbmloIGRhdG9nIHByZWR1emVjYSBtb3plbW8gbmFjaSB1IHBvbGp1IEFPUCA2MDUgemEgdGFqIG1hdGljbmkgYnJvaiwgaWxpIG5hIHByaW1lciB2cmVkbm9zdCBzdGFsbmUgaW1vdmluZSBpeiBiaWxhbnNhIHN0YW5qYSBzZSBuYWxhemkgdSBwb2xqdSBBT1AgMDAxLiBNZWRqdXRpbSB1c2xlZCBtZW5qYW5qYSBrb250bm9nIG9rdmlyYSBub3ZpIEFPUC1pIHNhZGEgaW1hanUgNCAgdW1lc3RvIDMgY2lmcmUgdGFrbyBkYSBnb3JlIG5hdmVkYW5lIGR2ZSB2YXJpamFibGUgc2Ugc2FkYSBuYWxhemUgcG9kIEFPUC1pbWEgOTAwNSBpIDAwMDIgcmVzcGVrdGl2bm8uIE1lZGp1dGltIG5lbW9ndWNlIGplIHByZW1hcGlyYXRpIHN2ZSBBT1AtZSBwbyBzdGFyb20gbmFjaW51IGl6dmVzdGF2YW5qYSBzYSBBT1AtaW1hIHBvIG5vdm9tIG5hY2ludSBpenZlc3RhdmFuamEgamVkYW4gbmEgamVkYW4gcGEgamUgc2FtaW0gdGltIGJpbG8gaSBuZW1vZ3VjZSBwcmlrYXphdGkgdGFiZWxhIHNhIHZhcmlqYWJsYW1hIGtvamUgdWNlc3R2dWp1IHUgcHJvcmFjdW51IGZpbmFuc2lqc2tpaCByYWNpamEsIHZlYyBzdSBzYW1vIHByaWthemFuaSBmaW5hbnNpanNraSByYWNpamkga2FvIGtyYWpuamkgcmV6dWx0YXQuDQo8L3A+DQoNCkNpbGogamUgc3Bvaml0aSBvdmEgZHZhIGNzdiBmYWpsYSB1IGplZGFuLiBVY2l0YW1vIGZpbmFuc2lqc2thIHJhY2lqYSBkbyAyMDEzLiBnb2RpbmU6DQpgYGB7cixldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KI2dlbmVyYWxuZSBvcGNpamUgaSB1Y2l0YXZhbmplIHBvdHJlYm5paCBiaWJsaW90ZWthDQppZihyZXF1aXJlKCdyZWFkcicpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdyZWFkcicpO3JlcXVpcmUoJ3JlYWRyJyl9DQppZihyZXF1aXJlKCJkYXRhLnRhYmxlIixxdWlldGx5ID0gRikgPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJkYXRhLnRhYmxlIik7cmVxdWlyZSgiZGF0YS50YWJsZSIscXVpZXRseSA9IEYpfQ0KaWYocmVxdWlyZSgnRFQnKT09Ril7aW5zdGFsbC5wYWNrYWdlcygnRFQnKTtyZXF1aXJlKCdEVCcpfQ0KaWYocmVxdWlyZSgnZTEwNzEnKT09Ril7aW5zdGFsbC5wYWNrYWdlcygnZTEwNzEnKTtyZXF1aXJlKCdlMTA3MScpfQ0KaWYocmVxdWlyZSgncnBpdm90VGFibGUnKT09Ril7aW5zdGFsbC5wYWNrYWdlcygncnBpdm90VGFibGUnKTtyZXF1aXJlKCdycGl2b3RUYWJsZScpfQ0KaWYocmVxdWlyZSgnY293cGxvdCcpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdjb3dwbG90Jyk7cmVxdWlyZSgnY293cGxvdCcpfQ0KaWYocmVxdWlyZSgncGxvdFJPQycpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdwbG90Uk9DJyk7cmVxdWlyZSgncGxvdFJPQycpfQ0KaWYocmVxdWlyZSgncFJPQycpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdwUk9DJyk7cmVxdWlyZSgncFJPQycpfQ0KaWYocmVxdWlyZSgiSW5mb3JtYXRpb25WYWx1ZSIpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJJbmZvcm1hdGlvblZhbHVlIik7cmVxdWlyZSgiSW5mb3JtYXRpb25WYWx1ZSIpfQ0KaWYocmVxdWlyZSgiSW5mb3JtYXRpb24iKT09Ril7aW5zdGFsbC5wYWNrYWdlcygiSW5mb3JtYXRpb24iKTtyZXF1aXJlKCJJbmZvcm1hdGlvbiIpfQ0KaWYocmVxdWlyZSgiZ3Rvb2xzIik9PUYpe2luc3RhbGwucGFja2FnZXMoImd0b29scyIpO3JlcXVpcmUoImd0b29scyIpfQ0KaWYocmVxdWlyZSgiZm9yZWNhc3QiKT09Ril7aW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKTtyZXF1aXJlKCJmb3JlY2FzdCIpfQ0KaWYocmVxdWlyZSgic3BlZWRnbG0iKT09Ril7aW5zdGFsbC5wYWNrYWdlcygic3BlZWRnbG0iKTtyZXF1aXJlKCJzcGVlZGdsbSIpfQ0KaWYocmVxdWlyZSgibWx0b29scyIpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJtbHRvb2xzIik7cmVxdWlyZSgibWx0b29scyIpfQ0KaWYocmVxdWlyZSgiRE13UiIpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJETXdSIik7cmVxdWlyZSgiRE13UiIpfQ0KDQpgYGAgIA0KDQpgYGB7cn0NClBva2F6YXRlbGppX3N0YXJpIDwtIHJlYWRfZGVsaW0oIkM6L1VzZXJzL21pbG9zLmNpcG92aWMvRGVza3RvcC9Qcm9qZWt0aS9FYXJseSB3YXJuaW5nL1JhenZvam5pIGZvbGRlci9Cb3R0b20gVXAvS29yYWsgMy9Qb2themF0ZWxqaS9Qb2themF0ZWxqaSBzdGFyaS5jc3YiLCI7IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCBjb2xfdHlwZXMgPSBjb2xzKERhdHVtID0gY29sX2RhdGUoZm9ybWF0ID0gIiVtLSVkLSVZIikpLCBsb2NhbGUgPSBsb2NhbGUoZW5jb2RpbmcgPSAiQVNDSUkiKSwgdHJpbV93cyA9IFRSVUUsIHByb2dyZXNzID1GQUxTRSkNCmdjKCkNCmBgYA0KDQpVY2l0YW1vIGZpbmFuc2lqc2thIHJhY2lqYSBwb3NsZSAyMDEzLiBnb2RpbmUNCmBgYHtyLCBldmFsPUZBTFNFfQ0KUG9rYXphdGVsamlfbm92aSA8LQ0KICByZWFkX2RlbGltKA0KICAiQzovVXNlcnMvbWlsb3MuY2lwb3ZpYy9EZXNrdG9wL1Byb2pla3RpL0Vhcmx5IHdhcm5pbmcvUmF6dm9qbmkgZm9sZGVyL0JvdHRvbSBVcC9Lb3JhayAzL1Bva2F6YXRlbGppL1Bva2F6YXRlbGppIG5vdmkuY3N2IiwNCiAgIjsiLA0KICBlc2NhcGVfZG91YmxlID0gRkFMU0UsDQogIGNvbF90eXBlcyA9IGNvbHMoRGF0dW0gPSBjb2xfZGF0ZShmb3JtYXQgPSAiJW0tJWQtJVkiKSksDQogIGxvY2FsZSA9IGxvY2FsZShlbmNvZGluZyA9ICJBU0NJSSIpLA0KICB0cmltX3dzID0gVFJVRSwNCiAgcHJvZ3Jlc3MgPUYgDQogICkNCiAgZ2MoKQ0KYGBgDQoNClNwYWphbW8gdGFiZWxlIGBQb2themF0ZWxqaV9zdGFyaWAgaSBgUG9rYXphdGVsamlfbm92aWAgdSBqZWRudSB0YWJlbHUsIG92ZSBkdmUgdGFiZWxlIHN1IHVzdHZhcmkgcHJlZHN0YXZsamFsZSBwcm9yYWN1bmF0YSBmaW5hbnNpanNrYSByYWNpamEuICBUYWJlbGUgc3UgZG9iaWplbmUgcHJldGhvZG5vbSBhbmFsaXRpa29tIGkgb2JyYWRvbSBwb2RhdGFrYSB1IGV4Y2VsdSBqZXIgbmlqZSBiaWxvIG1vZ3VjZSBkcnVnYWNpamUuLiBQb2tyZcSHZW1vIGByZWFkX0tBNF9SS19kYXRhYCBmdW5rY2lqdSB6YSBwcmlwcmVtYW5qZSBLQTQgaSBSSyBpenZlc3RhamEuIEtyZWlyYW5qZSBgTkJTX2RhdGFgIGZ1bmtjaWplIGplIHZlYyByYW5pamUgb3Bpc2FubyB1IHNjcmlwdHUgPGZvbnQgY29sb3I9InJlZCI+J35cXEVhcmx5IHdhcm5pbmdcXEJvdHRvbSBVcFxcS29yYWsgNFxcRWFybHkgd2FybmluZ1xcbmJzX2RhdGFfcHJlcC5SJzwvZm9udD4ga29qaSBzYWRyemkgc3VzdGluc2tpIGlzdGkga29kIGtvamkgaSBmdW5rY2lqYSBgcmVhZF9LQTRfUktfZGF0YWAuDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsZXZhbD1GQUxTRX0NCkFQUl9kYXRhIDwtIHJiaW5kLmRhdGEuZnJhbWUoUG9rYXphdGVsamlfc3RhcmksIFBva2F6YXRlbGppX25vdmkpDQpybShQb2themF0ZWxqaV9zdGFyaSAsIFBva2F6YXRlbGppX25vdmkpDQpnYygpDQoNCg0Kc291cmNlKCJuYnNfZGF0YV9wcmVwX2Z1bmN0aW9uLlIiKQ0KS0E0X3VybCA9ICJDOi9Vc2Vycy9taWxvcy5jaXBvdmljL0Rlc2t0b3AvQmF6ZSBwb2RhdGFrYS9LNCBpIEFQUiBpIE5QTC9LQTRfcG9kYWNpLnR4dCINClJLX3VybCA9ICJDOi9Vc2Vycy9taWxvcy5jaXBvdmljL0Rlc2t0b3AvQmF6ZSBwb2RhdGFrYS9LNCBpIEFQUiBpIE5QTC9SS19ub3ZpLnR4dCINCk5CU19kYXRhIDwtIHJlYWRfS0E0X1JLX2RhdGEoS0E0X3VybCwgUktfdXJsLCBjb25zZXF1dGl2ZV9kaWZvbHQ9RikNCg0KYGBgDQoNClNwYWphbW8gQVBSIGkgTkJTIHBvZGF0a2UgaSBpemJhY3VqZW1vIGtvbG9udSBgTmF6aXZTZWt0b3JgIGplciBwcmF2aSBwcm9ibGVtZSBwcmkgZWtzcG9ydHUuIFBvc3Rvamkgc2lmcm92YW5hIHZlcnppamEgb3ZlIGtvbG9uZSB0YWtvIGRhIHNtbyB1IHJlZHUsIHByZXppdmVjZW1vIGJleiBuamUuIFRha28gZGEgc2FkYSBpbWFtbyBwb2NldG51IHRhYmVsdSBzYSBwb2RhY2ltYSBrb2plIHBvc2VkdWplIE5CUyBvIGR1em5pY2ltYSBrb2ppIHNlIG5hbGF6ZSB1IGJhemkgQVBSLWEuIE9kIHBvZGF0YWthIGtvamUgcG9zZWR1amUgTkJTIG5hanZlY2kgem5hY2FqIG5hbSBwcmVkc3RhdmxqYSBpbmRpa2F0b3IgKmRpZm9sdGEqIGtvamkgbmFtIGdvdm9yaSBkYSBsaSBjZSBwb3NtYXRyYW5pIGR1em5payBzYSBzcmFjdW5hdGltIGZpbmFuc2lqc2tpbSByYWNpamltYSBpeiBBUFIgYmF6ZSBvdGljaSB1ICpkaWZvbHQqIHphIGR2ZSBnb2RpbmUgaWxpIG5lLg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCmMgPSBtZXJnZSgNCiAgTkJTX2RhdGEsDQogIEFQUl9kYXRhLA0KICBieS54ID0gYygiTUFUX0JSX0RVWk5JS0EiLCAiREFUVU0ueCIpLA0KICBieS55ID0gYygiSm1iIiwgIkRhdHVtIikNCiAgKQ0KICAjcm0oQVBSX2RhdGEsTkJTX2RhdGEpDQogIGMgPSBhcy5kYXRhLnRhYmxlKGMpDQogIGNbLCBOYXppdlNla3RvciA6PSBOVUxMXQ0KYGBgDQpLYW8gcHJ2aSBrb3JhayB1IGRhbGpvaiBhbmFsaXppIHBvdHJlYm5vIGplIHByZSBzdmVnYSBvYnJhdGl0aSBwYXpuanUgbmEgbG9naWNub3N0IHVuZXNlbmloIHZyZWRub3N0aSBrYW8gaSBuYSBuZWRvc3RhanVjZSB2cmVkbm9zdGksIHRqLiBwcm9yYWN1bmF0aSBwcm9jZW5hdCBuZWRvc3RhanVjaWggdnJlZG5vc3RpLiBOZWxvZ2ljbm9zdGkgamUgbmFqbGFrc2UgcHJvdmVyaXRpIHByZWdsZWRvbSBzdW1hcm5paCBzdGF0aXN0aWthIHRha28gZGEgY2UgbmFtIHNsZWRlY2EgdGFiZWxhIHBvbW9jaSB1IHRvbWUuICANCg0KIyMgMi4gUHJlbGltaW5hcm5hIGFuYWxpemEgcG9kYXRha2ENCioqVGFiZWxhIDEuKiogcHJpa2F6dWplIGFyaXRtZXRpY2t1IHNyZWRpbnUsIHRyaW1vdmFudSB2cmVkbm9zdCBpc3RlLCB6YXRpbSBtZWRpamFudSwgc3RhbmRhcmRudSBkZXZpamFjaWp1LCB0cmVjaSBpIGNldHZydGkgc3RhdGlzdGlja2kgbW9tZW50LCBtaW5pbWFsbnUgaSBtYWtzaW1hbG51IHZyZWRub3N0IGthbyBpIHUgcG9zbGVkbmplbSByZWR1IHByb2NlbmF0IG5lZG9zdGFqdWNpaCB2cmVkbm9zdGkuIFUgdG9rdSBwcmlwcmVtZSBwb2RhdGFrYSB1IGV4Y2VsdSBwb2plZGluaSByYWNpamkgbmlzdSBtb2dsaSBiaXRpIHNyYWN1bmF0aSB1c2xlZCBuZWRvc3RhamFuamEgQU9QLWEgemEgZGF0dSBvcHNlcnZhY2lqdSwgcG9zbGVkaWNubyByYWNpbyBkYXRlIG9ic2VydmFjaWplIGNlIGltYXRpIHZyZWRub3N0IGlsaSBgI04vQWAgaWxpIGAjRElWLzAhYC4gT3ZlIGR2ZSB2cmVkbm9zdGkgY2VtbyB1IG5hc3Rhdmt1IHRyZXRpcmF0aSBrYW8gbmVkb3N0YWp1Y2UgamVyIG9uZSB0byB1IHN2b2pvaiBwcmlyb2RpIGkgamVzdS4gT3ZkZSBzbW8gaWggemFtZW5pbGkgbmVkb3N0YWp1Y2ltICpgTkFgKiB2cmVkbm9zdGltYSB1IFItdS4gDQoNCg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsZXJyb3I9RkFMU0UsIGVycm9yPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI3phbWVuanVqZW0gI0RJVi8wISBpICNOL0Egc2EgZGlmb2x0bm9tIHZyZWRub3N0aSB6YSBuZWRvc3RhanVjZSB2cmVkbm9zdGkgdSBSLXUNCmIgPC0gYw0KYiA8LSBhcy5kYXRhLmZyYW1lKGIpDQpmb3IgKGkgaW4gMjE6NTApIHsNCiAgdGVtcCA8LSBiWywgaV0NCiAgdGVtcFt0ZW1wID09ICIjTi9BIiB8IHRlbXAgPT0gIiNESVYvMCEiXSA8LSBOQQ0KICBiWywgaV0gPC0gdGVtcA0KICBiWywgaV0gPC0gYXMubnVtZXJpYyhiWywgaV0pDQp9DQoNCiNza2xhbmphbSBuZXBvdHJlYm5lIHRhYmVsZSBkYSBvc2xvYm9kaW0gbWVtb3JpanUgamVyIG1vcmEgc2UuLi5rYW8gaSBzdnVkYSBkbyBzYWRhDQpybSh0ZW1wLGksS0E0X3VybCxSS191cmwscmVhZF9LQTRfUktfZGF0YSxBUFJfZGF0YSkNCg0KI2tyZWlyYW0gZHVwbGlrYXQgdGFiZWxlIG5hIGtvbSBjdSBkYSBkYWxqZXJhZGltIGkgemFkcnphdmFtIHNhbW8gYml0bmUga29sb25lLA0KI3RqLiBuZWtlIGNlIG1pIGJpdGkgcG90cmVibmUga2FzbmlqZSBhbGkgemEgbmppaCBzYW0gc2lndXJhbiBkYSBzdSBvayBqZXIgc2FtIGloIGtyZWlyYW8gaSB2ZWMgcHJvdmVyaW8NCiN1IHByb2NlZHVyaSBrcmVpcmFuamEgcG9kYXRha2EgaXogYmFua2Fyc2tvZyBzZWt0b3JhDQpiIDwtIGRhdGEudGFibGUoYikNCmNsZWFuX2IgPC0gYlssIGMoMSwgNCwgMiwgOSwgNSwgNywgMTQsIDE2OjUwKV0NCg0KI2tyZWlyYW0gZnVua2NpanUgemEgcHJvcmFjdW4gc3VtbWFyeSBzdGF0aXN0aWthDQpteS5zdW1tYXJ5IDwtIGZ1bmN0aW9uKHgsIGFyZz1UKXsNCiAgeDwtYXMubWF0cml4KHgpDQogIG48LW5yb3coeCkNCiAgZGF0YS5mcmFtZShtZWFuPW1lYW4oeCwgbmEucm09YXJnKSwNCiAgICBUcmltbWVkX21lYW49bWVhbih4LHRyaW0gPSAwLjEsbmEucm09YXJnKSwNCiAgICBzZD1zZCh4LCBuYS5ybT1hcmcpLA0KICAgIG1lZGlhbj1tZWRpYW4oeCwgbmEucm09YXJnKSwNCiAgICBza2V3bmVzcz1lMTA3MTo6c2tld25lc3MoeCxuYS5ybT1hcmcpLA0KICAgIGt1cnRvc2lzPWUxMDcxOjprdXJ0b3Npcyh4LG5hLnJtPWFyZyksDQogICAgbWluPW1pbih4LCBuYS5ybT1hcmcpLA0KICAgIG1heD1tYXgoeCxuYS5ybT1hcmcpLCANCiAgICBGaXJzdF9xdWFydGlsZT1xdWFudGlsZSh4LDAuMjUsbmEucm09YXJnKSwNCiAgICBUaGlyZF9xdWFydGlsZT1xdWFudGlsZSh4LDAuNzUsbmEucm09YXJnKSwNCiAgICBuPWxlbmd0aCh4KSwNCiAgICBOQXNwZXJjZW50PXJvdW5kKHN1bShhcy5udW1lcmljKGlzLm5hKHgpKS9uKSoxMDAsMSkNCiAgICApDQp9DQoNCiNrcmVpcmFtIHN1bWFybnUgdGFiZWx1DQpzdW1tYXJ5X3RhYmxlMSA8LSBzYXBwbHkoY2xlYW5fYlssIDExOjQyXSwgbXkuc3VtbWFyeSwgYXJnID0gVCkNCg0KDQojcHJpbnR1amVtIGplIHUgbm90ZWJvb2sNCg0KdHJfc3VtbWFyeV90YWJsZTEgPC0gdChzdW1tYXJ5X3RhYmxlMSkNCmZvcm1hdFJvdW5kKA0KICBkYXRhdGFibGUodHJfc3VtbWFyeV90YWJsZTEsIGNhcHRpb24gPSAiVGFiZWxhIDEuOlN1bWFybmkgcHJpa2F6IiwNCiAgICAgICAgICAgIGZpbHRlciA9ICdub25lJyksDQogIGNvbHVtbnMgPSBjb2xuYW1lcyh0cl9zdW1tYXJ5X3RhYmxlMSkNCikNCg0KYGBgDQoNCg0KDQojIyMgMi4xIE5lbG9naWNuaSB1bm9zaSAgDQpVIG92b20ga29yYWt1IGplIHBvdHJlYm5vIHByZSBzdmVnYSBwcmVnbGVkYXRpIGthdGVnb3JpY2tlIHZhcmlqYWJsZSB6YSBuZWxvZ2ljbmUgdW5vc2UsIG5haW1lLCBwcmltZWNlbm8gamUgZGEgdmFyaWphYmxhIGtvamEgYmkgdHJlYmFsbyBkYSBvem5hY2F2YSB2ZWxpY2ludSBkdXpuaWthIGkgdXppbWEgdnJlZG5vc3RpIG9kIDEgZG8gNCBzYWRyemkgdnJlZG5vc3RpIGtvamUgc3Ugem5hY2Fqbm8gdmVjZVteMV0sIHRha29kamUsIG1hbG8gamUgdmVyb3ZhdG5vIGRhIGplIHByb3NlY2FuIGJyb2ogemFwb3NsZW5paCBpem5vc2kgYHIgcm91bmQoYXMubnVtZXJpYyh0cl9zdW1tYXJ5X3RhYmxlMVsxLDFdKSlgLiBVdmlkb20gdSBwb2RhdGtlIGRvc2xvIHNlIGRvIHpha2xqdWNrYSBkYSBzdSBkYXRlIG5lbG9naWNub3N0aSByZXp1bHRhdCByYXpsaWtlIHUgc3RydWt0dXJpIGl6dmVzdGFqYSBmaW5hbnNpanNraWggaW5zdGl0dWNpamEgaSBvc3RhbGloIGxpY2Ega29qYSBzdSBkdXpuYSBkYSBwb2RhdGtlIHVub3NlIHUgQVBSIGJhenUsIHRha28gZGEgQU9QIDYwMiBrb2QgZmluYW5zaWpza2loIGluc3RpdHVjaWphIG5lIHByZWRzdGF2bGphIHNpZnJ1IHZlbGljaW5lLCBpc3RvIHZhemkgaSB6YSBwb2xqZSBrb2plIG96bmFjYXZhIHNpZnJ1IGJyb2phIHphcG9zbGVuaWguIERhbGppbSB1dmlkb20gZG9sYXppIHNlIGRvIGpvcyBuZWtpaCBzYXpuYW5qYSB1IGtvbnppc3RlbnRub3N0aSBBT1AtYSA2MDIga29qaSBvem5hY2F2YSB2ZWxpY2ludSBsaWNhLCBuYWltZSwgb3Rrcml2ZW5vIGplIGpvcyBqZWRubyBwb2xqZSB1IGJhemkga29qdSBOQlMgcG9zZWR1amUsIGEga29qZSBub3NpIGluZm9ybWFjaWplIG8gdmVsaWNpbmkgbGljYSwgb3ZvIHBvbGplIG5lbWEgc2lmcnUgQU9QLWEuIFBvc2xlIHByb3ZlcmUgcG9kYXRha2Ega29qZSBwb3NlZHVqZW1vIGkgbmppaG92aW0gdXBvcmVkaml2YW5qZW0gc2EgdnJlZG5vc3RpbWEgc2EgQVBSIHNhanRhIG9wcmVkZWxpbGkgc21vIHNlIHphIEFPUCA2MDIuIFByZXRob2RubyBvcGlzYW5hIGR2YSBwb2xqYSBzdSBzZSB1IHBvamVkaW5pbSBzbHVjYWpldmltYSByYXpsaWtvdmFsYSwgemJvZyB0b2dhIGplIGkgaXp2cnNlbmEgYW5hbGl6YS4gTmFpbWUsIHBvbWVudXRvIHBvbGplIGtvamUgc2UgbmFsYXppIHUgcGl2b3QgdGFiZWxhbWEgKG5hY2luIG5hIGtvamkgTkJTIGltYSBwcmlzdHVwIEFQUiBiYXppKSBqZSB1IG9kcmVkamVub20gYnJvanUgc2x1Y2FqZXZhIHByaWtheml2YWxvIHBvZGF0a2Ugb2QgcHJldGhvZG5lIGdvZGluZS4gT3ZvIGplIHNsdWNhaiBzYW1vIHNhIHN0YXJpbSBuYWNpbm9tIGl6dmVzdGF2YW5qYSwgZGFrbGUgZG8gMjAxMy4gZ29kaW5lISAgDQpOYXN0YXZsamFtbyBzYSBhbmFsaXpvbSB0YWtvIHN0byBjZW1vIGl6YmFjaXRpIGl6IHRhYmVsZSBvYnNlcnZhY2lqZSBzYSB2cmVkbm9zdGltYSB1IGtvbG9uaSBgVmVsaWNpbmFgIHZlY2ltIG9kIDQgaSBtYW5qaW0gb2QgMSBpIHBvbm92byBwcmVnbGVkYXRpIHN0cnVrdHVydSBzdW1hcm5lIHRhYmVsZS4gTmFrbmFkbm8sIGl6YmFjaWNlbW8gc3ZhIGxpY2Ega29qYSBuZSBwcmlwYWRhanUgZ3J1cGkgPGZvbnQgY29sb3I9cmVkPiJQcml2cmVkbmloIGRydXN0YXZhIGkgemFkcnVnYSI8L2ZvbnQ+IG9iemlyb20gZGEgbmFydXNhdmFqdSBob21vZ2Vub3N0IHV6b3JrYSBrYW8gaSBkYSBpbSBBT1AgcG96aWNpamUgbmlzdSBtYXBpcmFuZSBrYW8gUHJpdnJlZG5pbSBkcnVzdGF2aW1hIGkgemFkcnVnYW1hIHBhIHN1IHNhbWltIHRpbSB0ZSBvYnNlcnZhY2lqZSBpIGdsYXZuaSB1enJvayBuZWtvbnppc3RlbnRub3N0aSB1IHBvZGFjaW1hLiAgIA0KDQpVdmlkb20gdSAqKlRhYmVsdSAyLioqIGkgcG9samEgYFZlbGljaW5hYCBpIGBCcm9qIHphcG9zbGVuaWhgIHZpZGltbyBkYSBzdSBzcmVkbmphIHZyZWRub3N0LCBtaW5pbXVtIGkgbWFrc2ltdW0gdSBwcmlodmF0bGppdmltIGdyYW5pY2FtYS4gUG9zbWF0cmFuamUgb3N0YWxpaCB2YXJpamFibGkgYmkgemFodGV2YWxvIGRldGFsam5panUgYW5hbGl6dSBzdmFrZSBvZCBuamloIHBvbmFvc29iLiBPdmFqIGtvcmFrIGNlIGJpdGkgdXJhZGplbiBrYXNuaWplIHUgKnVuaXZhcmlhdGUqIGFuYWxpemkgdGFrbyBkYSBjZSBzYWRhIGJpdGkgcHJlc2tvY2VuLiANCg0KYGBge3IsICwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KI3VjaXRhdmFtIHVuYXByZWQgcHJpcHJlbWxqZW51IHRhYmVsdSBrb2phIG5hbSB6YSBwb3NtYXRyYW5pIG1iIGkgZ29kaW51IGRhamUgbmplZ292dSBwcmlwYWRub3N0IG9kcmVkamVub20gc2VrdG9ydSwgdGouIGdvdm9yaSBuYW0gaXoga29qZWcgamUgZmluYW5zaWpza29nIGl6dmVzdGFqYSBkYXRhIG9ic2VydmFjaWphIHUgQVBSLXUNCmdjKCkNCg0KUHJhdm5hX2Zvcm1hIDwtDQogIHJlYWRfZGVsaW0oDQogICJDOi9Vc2Vycy9taWxvcy5jaXBvdmljL0Rlc2t0b3AvUHJvamVrdGkvRWFybHkgd2FybmluZy9SYXp2b2puaSBmb2xkZXIvQm90dG9tIFVwL0tvcmFrIDUvUHJhdm5hIGZvcm1hLmNzdiIsDQogICJ8IiwNCiAgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLA0KICB0cmltX3dzID0gVFJVRSwNCiAgY29sX3R5cGVzID0gY29scyhEYXR1bSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlWSIpKSwNCiAgcHJvZ3Jlc3MgPSBGQUxTRQ0KICApDQoNCiNtZXJkenVqZW0gcG9pZGF0a2Ugc2EgY2xlYW5fYiwgdGouIHByZWNpc2NhdmFtIGNsZWFuX2IgdGFrbyBzdG8gcG9zdG8gbWVyZHp1amVtIHphZHJ6aW0gc2FtbyBvbmUgc2EgDQojc2Egc2lmcm9tIDE0MDAwIHN0byBwcmVkc3RhdmxqYSAiUHJpdnJlZG5hIGRydXN0YXZhIGkgemFkcnVnZSINCmNsZWFuX2IgPC0NCiAgbWVyZ2UoDQogIGNsZWFuX2IsDQogIFByYXZuYV9mb3JtYSwNCiAgYnkueCA9IGMoIkRBVFVNLngiLCAiTUFUX0JSX0RVWk5JS0EiKSwNCiAgYnkueSA9IGMoIkRhdHVtMSIsICJKbWIiKQ0KICApDQoNCg0KDQpjbGVhbl9iIDwtDQogIGNsZWFuX2JbU2lmcmEgPT0gMTQwMF1bLCBjKCJOYXppdiIsICJTaWZyYSIsICJOYXppdlByYXZub2dMaWNhIikgOj0gTlVMTF0NCiAgI2l6YmFjaW0gdnJlZG5vc3RpIHZlbGljaW5hIGtvamUgc3UgdmVjZSBvZCA0LCBkb3VibGUgY2hlY2sgaW5hY2UgbmUgYmkgc21lbG8gZGEgc21hbmppIGJyb2ogcmVkb3ZhDQpjbGVhbl9iIDwtIGNsZWFuX2JbVmVsaWNpbmEgPD0gNCAmIFZlbGljaW5hID4gMF0NCiNwb25vdm8ga3JlaXJhbSBkYXRhLmZyYW1lIHN1bW1hcnlfdGFibGUNCnN1bW1hcnlfdGFibGUgPC0gc2FwcGx5KGNsZWFuX2JbLCAxMTo0Ml0sIG15LnN1bW1hcnksIGFyZyA9IFQpDQojdHJhbnNwb251amVtDQp0cl9zdW1tYXJ5X3RhYmxlIDwtIHQoc3VtbWFyeV90YWJsZSkNCiNwcmludHVqZW0gdGFiZWx1DQoNCmZvcm1hdFJvdW5kKA0KICAgICAgICAgICAgZGF0YXRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgIHRyX3N1bW1hcnlfdGFibGUsDQogICAgICAgICAgICAgICAgICAgICAgY2FwdGlvbiA9ICJUYWJlbGEgMi46U3VtYXJuaSBwcmlrYXogYmV6IGJhbmFrYSBpIG9zdGFsaWggZmluYW5zaWpza2loIGluc3RpdHVjaWphIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSAnbm9uZScsDQogICAgICAgICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9ICdCdXR0b25zJywgDQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aD0xMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2NvcHknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnY3N2JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2V4Y2VsJw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAgDQogICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgIGNvbHVtbnMgPSBjb2xuYW1lcyh0cl9zdW1tYXJ5X3RhYmxlKQ0KICAgICAgICAgICApDQpgYGANCg0KIyMjIDIuMiBOZWRvc3RhanVjZSB2cmVkbm9zdGkgIA0KDQpUcmV0aXJhbmplIG5lZG9zdGFqdWNpaCB2cmVkbm9zdGkga2FvIGtvcmFrIHUgcmF6dm9qdSBtb2RlbGEgbm9zaSBkb2RhdG51IHRlemludSBpbWFqdWNpIHUgdmlkdSBkYSBjZSBiaXRpIHBvdHJlYm5vIHRyZXRpcmF0aSBuZWRvc3RhanVjZSB2cmVkbm9zdGkgaSB1IHByb2Nlc3Ugc2Ftb2cgcHJlZHZpZGphbmphIHNvbHZlbnRub3N0aSBiYW5rZSAoYSB0byBqZSBrcmFqbmppIGNpbGogb3ZlIGFuYWxpemUpIHBvc3RvIGplIG1vZGVsIGV2YWx1aXJhbi4gU2FtaW0gdGltLCB1dmlkb20gdSBsaXRlcmF0dXJ1IG8gbmFqYm9samltIHByYWtzYW1hIHRyZXRtYW5hIG5lZG9zdGFqdWNpaCBvYnNlcnZhY2lqYSBvZGx1Y3VqZW1vIHNlIHphIHNsZWRlY2kgcG9zdHVwYWsga29qaSBqZSBwcmVkbG96ZW4gdSBrbmppemkgKkRldmVsb3BpbmcsIFZhbGlkYXRpbmcgYW5kIFVzaW5nIEludGVybmFsIFJhdGluZ3MqOiAgDQoNCiogICBSZWQgb2JzZXJ2YWNpamUgc2UgYnJpc2UgdWtvbGlrbyBuZWRvc3RhamUgdmlzZSBvZCA3NSUgcG9kYXRha2EgdSBuamVtdQ0KKiAgIEtvbG9uYSB2YXJpamFibGUgc2UgYnJpc2UgdWtvbGlrbyBpbWFqdSB2aXNlIG9kIDEwJSBuZWRvc3RhanVjaWggdnJlZG5vc3RpW14yXQ0KKiAgIFVrb2xpa28gbmVkb3N0YWplIG1hbmplIG9kIDEwJSBvYnNlcnZhY2lqZSBwb3NtYXRyYW5lIHZhcmlqYWJsZSB2cnNpIHNlIGltcHV0YWNpamEgKHphbWVuYSkgb2JzZXJ2YWNpamEgbWVkaWphbmltYSB2YXJpamFibGkuIE5hIG92YWogbmFjaW4gc2UgaXpiZWdhdmEgb3NldGxqaXZvc3QgbmEgYXV0bGFqZXJlIGtvanUgcG9zZWR1amUgc3JlZG5qYSB2cmVkbm9zdC4gUHJpIGNlbXUgc2UgbWVkaWphbmEgcG9zZWJubyBwcm9yYWN1bmF2YSB6YSB6ZHJhdmUgYSBwb3NlYm5vIHphIGR1em5pa2UgdSBzdGF0dXN1IG5laXptaXJlbmphIG9iYXZlemEuIE92bywgbWVkanV0aW0gbmlqZSBzbHVjYWoga29kIHZhbGlkYWNpb25vZyB1em9ya2EsIGthbyB0YWthdiBvbiBuZSBiaSB0cmViYW8gZGEgc2FkcnppIG5pa2FrdnUgaW5mb3JtYWNpanUgbyB0b21lIGRhIGxpIGNlIHBvc21hdHJhbmkgZHV6bmlrIHUgYnVkdWNub3N0aSBwcmVzdGF0aSBkYSBpem1pcnVqZSBzdm9qZSBvYmF2ZXplLCBzYW1pbSB0aW0gdSB2YWxpZGFjaW9ub20gdXpvcmt1IGthbyB2cmVkbm9zdCBpbnB1dGFjaWplIGtvcmlzdGltbyBtZWRpamFudSBrb21wbGV0IHZhcmlqYWJsZSwgbmV6YXZpc25vIG9kIHRvZ2EgZGEgbGkgcHJpcGFkYSBzb2x2ZW50bmltIGlsaSBuZXNvbHZlbnRuaW0gZHV6bmljaW1hLiAgDQoqICAgSW5kaWthdG9yaSBzZSB0cmFuc2Zvcm1pc3UgdSBrYXRlZ29yaWNrZSB2YXJpamFibGUgdWtvbGlrbyBwb3N0b2ppIGFwcmlvcmkgem5hbmplIG8gbmppaG92b20gem5hY2FqdSBpIHVrb2xpa28gbmUgcG9zdG9qZSBwcm9rc2kgaW5kaWthdG9yaSBrb2ppIGJpIHphbWVuaWxpIHBvc21hdHJhbmkgaW5kaWthdG9yLiAgDQoNClZhcmlqYWJsZSBrb2plIHByZWRzdGF2bGphanUgcHJvYmxlbSB1IHNtaXNsdSBwcm9jZW5hdGEgbmVkb3N0YWphbmphIHN1OiAgDQoNCiogICAqUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbykqIC0gb3ZhIHZhcmlqYWJsYSBqZSBuYSBncmFuaWNpIHBvIGdvcmVuYXZlZGVuaW0ga3JpdGVyaWp1bWltYQ0KKiAgIFJhY2lvX29icnRhX3BvdHJheml2YW5qYV9vZF9rdXBhY2ENCiogICBSYWNpb19vYnJ0YV9wb3Nsb3ZuZV9pbW92aW5lDQoqICAgUmFzdF9FQklUREENCiogICAqU3RvcGFfcHJpbm9zYV9uYV91a3VwbmFfc3JlZHN0dmFfcHJlX29wb3Jleml2YW5qYSogLSBvdmEgdmFyaWphYmxhIGplIG5hIGdyYW5pY2kgcG8gZ29yZW5hdmVkZW5pbSBrcml0ZXJpanVtaW1hDQoqICAgUmFzdF9wcmlob2RhX29kX3Byb2RhamUNCiogICBQb2tyaWNlX25ldG9fa2FtYXRhICAgDQoNClphcGF6YW1vIGRhIHNlIGJyaXNhbmplIG5lZG9zdGFqdWNpaCBvYnNlcnZhY2lqYSBwcmVwb3J1Y3VqZSB0ZWsgcG9zdG8gc3UgaXNwdW5qZW5pIG9kcmVkamVuaSB1c2xvdmkgYmV6IG9iemlyYSBuYSB2ZWxpY2ludSB1em9ya2EsIGJyaXNhbmplIG5lZG9zdGFqdWNpaCBvYnNlcnZhY2lqYSBiaSBnZW5lcmFsbm8gdHJlYmFsbyBkYSBidWRlIHBvc2xlZG5qYSBvcGNpamEgcHJpIGNpc2Nlbmp1IHBvZGF0YWthLiAgDQpKb3MgamVkbmEgY2luamVuaWNhIGNlIGltYXRpIHVkZW8gdSBpemJvcnUgdmFyaWphYmxpLiBQcmUgc3ZlZ2EgY2V0aXJpIHBva2F6YXRlbGphIHUgbGlzdGkgc3UgZGluYW1pY2tpIGkgcHJpa2F6dWp1IHN0b3B1IHJhc3RhIG9kcmVkamVuZSB2ZWxpY2luZSwgY2ltZSBzZSBndWJpIGplZG5hIChwcnZhKSBnb2RpbmEgb2JzZXJ2YWNpamEsIHNhbWltIHRpbSBvdmEgY2V0aXJpIHBva2F6YXRlbGphIGNlIHUgcHJ2b2ogZ29kaW5pIGltYXRpIHN2ZSBuZWRvc3RhanVjZSB2cmVkbm9zdGkuIE5hdm9kaW1vIG92ZSByYWNpamU6ICANCg0KKiAgIFJhY2lvIG9icnRhIHBvdHJhxb5pdmFuamEgb2Qga3VwYWNhOyAgDQoqICAgUmFjaW8gb2JydGEgcG9zbG92bmUgaW1vdmluZTsgIA0KKiAgIFJhc3QgRUJJVERBOyAgDQoqICAgUmFzdCBwcmlob2RhIG9kIHByb2RhamUuICANCg0KT2RsdWthIG8gYnJpc2FuanUgaWxpIHphZHJ6YXZhbmp1IG92aWggdmFyaWphYmxpIGNlIHByZXZhc2hvZG5vIHphdmlzaXRpIG9kIG5qaWhvdmUgZGlza3JpbWluYXRpdm5lIG1vY2kgcGEgemF0aW0gb2QgZ29yZSBuYXZlZGVuaWgga3JpdGVyaWp1bWEuIERvZGF0bm8gcG9qYXNuamF2YW1vIGRhIGJpIHphZHJ6YXZhbmplIG92aWggdmFyaWphYmxpIHNrcmF0aWxvIGNpdGF2IHV6b3JhayB6YSBwcnZ1IGdvZGludSBvYnNlcnZhY2lqYSwgcGEgY2UgaSB2ZWxpY2luYSB1em9ya2EgYml0aSBwcmVzdWRhbiBmYWt0b3IuDQoNClByZSBwcmltZW5lIGdvcmUgbmF2ZWRlbmloIHBvc3R1cGFrYSB2YXpubyBqZSBuYXZlc3RpIGRhIGNlbW8gbWkgcmFkaXRpIHRyaSBtb2RlbGEsIHUgemF2aXNub3N0aSBvZCB2ZWxpY2luZSBkdXpuaWthLiBTYW1hIHBvZGVsYSBjZSBiaXRpIGl6dnJzZW5hIG5hIG9zbm92dSB2YXJpamFibGUgYFZlbGljaW5hYCBrb2phIHJhenZyc3RhdmEgbGljYSBwcmVtYSB1bmFwcmVkIHV0dnJkamVuaW0ga3JpdGVyaWp1bWltYSBBUFItYSB2aWRldGkgW0FQUi8i0JrRgNC40YLQtdGA0LjRmNGD0LzQuCDQt9CwINGA0LDQt9Cy0YDRgdGC0LDQstCw0ZrQtSDQuCDQs9GA0LDQvdC40YfQvdC1INCy0YDQtdC00L3QvtGB0YLQuCDQt9CwIDIwMTYuINCz0L7QtNC40L3RgyJdKGh0dHA6Ly93d3cuYXByLmdvdi5ycy/QoNC10LPQuNGB0YLRgNC4L9Ck0LjQvdCw0L3RgdC40ZjRgdC60LjQuNC30LLQtdGI0YLQsNGY0Lgv0KDQsNC30LLRgNGB0YLQsNCy0LDRmtC10L/RgNCw0LLQvdC40YXQu9C40YbQsC/QmtGA0LjRgtC10YDQuNGY0YPQvNC40LfQsNGA0LDQt9Cy0YDRgdGC0LDQstCw0ZrQtdC40LPRgNCw0L3QuNGH0L3QtdCy0YDQtdC00L3QvtGB0YLQuC5hc3B4KS4gVSBjaWxqdSB1emltYW5qYSB1IG9iemlyIHZlbGljaW5lIGl6bG96ZW5vc3RpIGtvcmlzdGljZW1vIGkgdmFyaWphYmx1IGtvamEgcHJlZHNhdmxqYSB1ZGVvIGl6bG96ZW5vc3RpIHBvc21hdHJhbm9nIGR1em5pa2EgdSBrYXBpdGFsdSBiYW5rZSBrb2phIGplIHByZW1hIG5qZW11IGl6bG96ZW5hLiBPdmEgdmFyaWphYmxhIGNlIGJpdGkgbmFrbmFkbm8gc3JhY3VuYXRhIGkgaW1hIHphIGNpbGogZGEgdXptZSB1IG9iemlyIHJhemxpY2l0IHRyZXRtYW4gcHJlbWEgZHV6bmlrdSBwcmVtYSBuamVnb3ZvaiB2ZWxpY2luaSBwb3NtYXRyYW5vIHNhIHN0YW5vdm5pc3R2YSBiYW5rZS4gQnVkdWNpIGRhIHN1IG9kcmVkamVuaSBkdXpuaWNpIHphZHV6ZW5pIGtvZCB2aXNlIGJhbmFrYSBwb3NtYXRyYWNlIHNlIHNhbW8gb25lIGJhbmtlIHUga29qaW1hIGplIGRhdGkgZHV6bmlrIG5hanZpc2UgemFkdXplbi4gT3ZvIGplIHVqZWRubyBpIHJlenVsdGF0IHJhbmlqZSBvYnJhZGUgcG9kYXRha2EgaXogS0E0IGkgUksgb2JyYXNjYSAodmlkZXRpIHNrcmlwdCA8Zm9udCBjb2xvcj1yZWQ+In5FYXJseSB3YXJuaW5nXFxuYnNfZGF0YV9wcmVwLlIiPC9mb250PikgZ2RlIHN1IG8gb3ZpbSBzbHVjYWpldmltYSB2aXNlc3RydWtlIGl6bG96ZW5vc3RpIHNhY3V2YW5lIG9ic2VydmFjaWphIGtvZCBiYW5ha2EgcHJlbWEga29qaW1hIHBvc2VkdWp1IG5hanZlY2EgZHVnb3ZhbmphLiBQcmUgcG9jZXRrYSAqdW5pdmFyaWF0ZSogYW5hbGl6ZSBwb3RyZWJubyBqZSBwcm9yYWN1bmF0aSB2ZWMgc3BvbWVudXRpIHVkZW8gaXpsb3plbm9zdGkgcG9zbWF0cmFub2cgZHV6bmlrYSB1IHJlZ3VsYXRvcm5vbSBrYXBpdGFsdSBiYW5rZS4gVG8gY2VtbyB1cmFkaXRpIHRha28gc3RvIGNlbW8gaW5wb3J0b3ZhdGkgdmVjIHByaXByZW1samVudSB0YWJlbHUgc2Egc2VyaWpvbSB2cmVkbm9zdGkgcmVndWxhdG9ybm9nIGthcGl0YWxhIGJhbmFrYS4gIA0KYGBge3J9DQojdWNpdGF2YW0gc2VyaWp1IHJlNGd1bGF0b3Jub2cga2FwaXRhbGEgemEgYmFua2UNCnJlZ3VsYXRvcnlfY2FwaXRhbCA8LSByZWFkX2RlbGltKA0KICAiQzovVXNlcnMvbWlsb3MuY2lwb3ZpYy9EZXNrdG9wL1Byb2pla3RpL0Vhcmx5IHdhcm5pbmcvUmF6dm9qbmkgZm9sZGVyL0JvdHRvbSBVcC9Lb3JhayA1L3JlZ3VsYXRvcnlfY2FwaXRhbC5jc3YiLA0KICAiOyIsDQogIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwNCiAgY29sX3R5cGVzID0gY29scyhEYXR1bSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlZC4lbS4lWSIpKSwNCiAgdHJpbV93cyA9IFRSVUUNCikNCg0KI3ByaWxlcGxqdWplbSBqZSB6YSBjbGVhbl9iIHRhYmVsdQ0KY2xlYW5fYiA8LQ0KICBtZXJnZSgNCiAgY2xlYW5fYiwNCiAgcmVndWxhdG9yeV9jYXBpdGFsLA0KICBieS54ID0gYygiREFUVU0ueCIsICJNQVRJQ05JX0JST0oueCIpLA0KICBieS55ID0gYygiRGF0dW0iLCAiTUIiKQ0KICApDQoNCiNwcm9yYWN1bmF2YW0gdWRlbyBpemxvemVub3N0aSBpIG9kc3RyYW5qdWplbSBrb2xvbmUgdmlza2Ega29qZSBzdSBkb3NsZSBzYSB0YWJlbG9tIHJlZ3VsYXRvcnlfY2FwaXRhbA0KY2xlYW5fYiA8LQ0KICBjbGVhbl9iWywgdWRlb191X2thcGl0YWx1IDo9IChJWkxPWkVOT1NULnggLyBCcm9qaWxhYykgKiAxMDAwXSNza2FsaXJhbm8gemJvZyBudW1lcmlrZQ0KICBjbGVhbl9iIDwtIGNsZWFuX2JbLCBjKCJCcm9qaWxhYyIsICJJbWVuaWxhYyIsICJQb2themF0ZWxqIikgOj0gTlVMTF0NCg0KI2Npc3RpbSBzbWVjZQ0KICBybSgNCiAgICBiLA0KICAgIFByYXZuYV9mb3JtYSwNCiAgICByZWd1bGF0b3J5X2NhcGl0YWwsDQogICAgc3VtbWFyeV90YWJsZSwNCiAgICBzdW1tYXJ5X3RhYmxlMSwNCiAgICB0cl9zdW1tYXJ5X3RhYmxlDQogICAgKQ0KICAgIGdjKCkNCmBgYA0KDQpbXjFdOiBPdmRlIHNlIHRvIG5lIHZpZGkgamVyIGplIHUgbWVkanV2cmVtZW51IHByZXByYXZsamVubywgdmlkaSByYXp2b2puaSBmb2xkZXIsIGtvcmFrZSAyLDMsNS4gT3NpbSB2ZWNpaCB2cmVkbm9zdGkga29qZSBzdSBzZSBqYXZpbGUgZG9zbG8gc2UgZG8gc2F6bmFuamEgZGEgdmVsaWNpbmEgcHJhdm5paCBsaWNhIHUgQVBSIGJhemkgbmlqZSBiaWxhIHByZXJhY3VuYXRhIHBvIGtyaXRlcmlqdW1pbWEgbm92b2cgemFrb25hLCB2aWRpIFtaYWtvbiBvIHJhY3Vub3ZvZHN0dnUgU2wuIGdsYXNuaWsgUlMgYnIuIDYyMjAxM10oaHR0cDovL3d3dy5pbmZ1c2UuY28ucnMvemFrb25pL3pfcmFjdW5vdm9kc3R2b182Ml8yMDEzLnBkZikgcGEgamUgb25hIG5ha25hZG5vIHByZXJhY3VuYXRhIHUgZXhjZWxpbWEgcG9zbGUgY2VnYSBqZSBvdmFqIHNrcmlwdCBwb25vdm8gcG9rcmVudXQgdGFrbyBkYSBzZSBvdmFqIHRla3N0IGtvamkgc2kgcHJvY2l0YW8gb2Rub3NpbyBuYSByYW5panUgdmVyemlqdS4uLixJbmNlcHRpb24uIA0KDQpbXjJdOiBWaWRlY2VtbyBrYXNuaWplIGRhIG92YWoga3JpdGVyaWp1bSB6YXZpc2kgaSBvZCBpc2t1c3R2YSBzYW1vZyBhdXRvcmEsIHRha28gbmEgcHJpbWVyIE9lTkIgaSBGTUEgKDIwMDQpIHByZXBvcnVjdWp1IGJyaXNhbmplIHVrb2xpa28gbmVkb3N0YWplIHZpc2Ugb2QgMjAlIHZyZWRub3N0aSBkb2sgc21vIG92ZGUgbmF2ZWxpIGl6dm9yIGtvamkgcHJlcG9ydWN1amUgYnJpc2FuamUgdmFyaWphYmxlIHVrb2xpa28gbmVkb3N0YWplIDEwJSB2cmVkbm9zdGkuICANCg0KTmEga3JhanUgcG9nbGVkYWptbyB0YWJlbHUgY2lzY2VuamEgcG9kYXRha2E6ICANCg0KIVtUYWJlbGEgMy46IFByZWdsZWQgb2JyYWRlIHBvZGF0YWthIG9kIHBvY2V0bmloIHBhIGRvIHBvZGF0YWthIGtvamkgdWxhemVdKHRhYmVsYS5wbmcpeyNpZCAuY2xhc3Mgd2lkdGg9MTUwMCBoZWlnaHQ9MTAwMH0NCg0KDQojIyAzLiAqIlVuaXZhcmlhdGUiKiBhbmFsaXphICANCl9fX19fX19fX19fX19fX19fX19fICANCjxwIHN0eWxlPSJjb2xvcjpncmF5O21hcmdpbi1sZWZ0OiA0MHB4O21hcmdpbi1yaWdodDogNDBweDt0ZXh0LWFsaWduOmp1c3RpZnk7Y29sb3I6Z3JheSI+IERvIHNhZGEgbmlzbW8gam9zIHV2ZWsgcmF6bWF0cmFsaSBrb250aW51YWxuZSB2YXJpamFibGUsIHJhemxvZyBqZSBiaW8gc3RvIHV6b3JhayBqb3MgdXZlayBuaWplIGJpbyBwb2RlbGplbiBuYSB0cmkgcG9kdXpvcmthIHUgemF2aXNub3N0aSBvZCB2ZWxpY2luZSBkdXpuaWthLiBQcmUgcG9jZXRrYSAqdW5pdmFyaWF0ZSogYW5hbGl6ZSByYXpkdm9qaWNlbW8gdXpvcmFrIG5hIHRyaSBkZWxhLiBQb3NlYm5vIGNlIHNlIGV2YWx1aXJhdGkgbW9kZWxpIHphIG1pa3JvIGkgbWFsYSwgc3JlZG5qYSBpIHZlbGlrYSBwcmVkdXplY2EuIFRha29kamUsIHRyZXRtYW4gbmVkb3N0YWp1Y2loIHZyZWRub3N0aSBqZSBzYW1vIGRlc2tyaXB0aXZubyBuYXZlZGVuIHUgc21pc2x1IG1ldG9kb2xvc2tvZyBwcmF2Y2EgdSBrb20gY2Ugc2UgaWNpIHByaSBvYnJhZGkuIFN2ZSBvdmUgYW5hbGl6ZSBpIG9uZSBrb2plIHNsZWRlIGNlIHNlIG9iYXZpdGkgcG9qZWRpbmFjbm8gemEgc3Zha3UgZ3J1cHUgZHV6bmlrYSBwb25hb3NvYi4gUHJlIG5lZ28gc3RvIHNlIHV6b3JhayByYXpkdm9qaSwgdSBvdm9qIHNla2NpamksIHVrcmF0a28gY2UgYml0aSBvcGlzYXRpIHJhY2lqaSBrb2ppIHN1IGtvcmlzY2VuaSwgbmppaG92YSBla29ub21za2EgbG9naWthIGkgb2Nla2l2YW51IHZlenUgc2EgdmVyb3ZhdG5vY29tICpkaWZvbHRhKiwgamVyIGNlIHNlIGlzdGkgc2V0IHJhY2lqYSBrb3Jpc3RpdGkgdSBzdmEgdHJpIHNsdWNhamEuIFBvIG9waXN1IHJhY2lqYSwgdSBuYXN0YXZrdSBvdmUgc2VrY2lqZSwgY2Ugc2UgaXNwaXRhdGkgYnJvaiBuZWRvc3RhanVjaWggdnJlZG5vc3RpIGkgbmppaG92IHRyZXRtYW4sIHByaXN1dG5vc3QgYXV0bGFqZXJhIGkgbmppaG92IHRyZXRtYW4sIHJhZG5hIGhpcG90ZXphLCBtb25vdG9ub3N0LCBtb2MgZGlza3JpbWluYWNpamUgaSBrb3JlbGFjaWphIHphIHN2YWtpIG9kIHRyaSBtb2RlbGEuIFN2aSBwcmV0aG9kbm8gbmF2ZWRlbmkgcG9zdHVwY2kgaW1hanUgemEgY2lsaiBzdG8gYm9sanUgcHJlZCBzZWxla2NpanUgdmFyaWphYmxpIHByZWQgdWx6YWsgdSB6YXZyc251IGZhenUgKm11bHRpdmFyaWF0ZSogYW5hbGl6dSBnZGUgY2UgKnN0ZXB3aXNlKiBwcm9jZWR1cm9tIGJpdGkgaXphYnJhbmkga29uYWNuaSBtb2RlbGk8L3A+ICANCg0KIyMjIDMuMSBGaW5hbnNpanNraSByYWNpamksIGVrb25vbXNrYSBsb2dpa2EgaSByYWRuYSBoaXBvdGV6YSAgDQoNCkthbyBwb2xhem5hIG9zbm92YSBwb3NsbyBzZSBvZCBwZXQgZ3J1cGEgcG9rYXphdGVsamEga29qaSBiaSwgaWRlYWxubywgdHJlYmFsbyBkYSBuYW0gZGFqdSBpbmZvcm1hY2lqdSBvOiAgDQoNCiogICBMaWt2aWRub3N0aQ0KKiAgIFNvbHZlbnRub3N0aQ0KKiAgIFByb2ZpdGFiaWxub3N0aQ0KKiAgIFBvc2xvdm5lIGFrdGl2bm9zdGkNCiogICBPc3RhbGkgcG9rYXphdGVsamkga29qZSBqZSB0ZXNrbyBzdnJzdGF0aQ0KDQoNClBva2F6YXRlbGppLCBuamlob3ZhIHByaXBhZG5vc3QgZ3J1cGkgaSBoaXBvdGV6YSBla29ub21za2UgbG9naWNub3N0aSBuamlob3ZlIHJlbGFjaWplIHNhIHZlcm92YXRub2NvbSBuYXN0dXBhbmphIG5laXptaXJlbmphIG9iYXZlemEgamUgcHJpa2F6YW5hIHUgc2xlZGVjb2ogdGFiZWxpOiAgDQoNCiFbVGFiZWxhIDQuOiBQb2xhem5pIHJhY2lqaSBrb2ppIHVsYXplIHUgdW5pdmFyaWF0ZSBhbmFsaXp1XSh0YWJlbGEyLnBuZyl7I2lkIC5jbGFzcyB3aWR0aD0xNTAwIGhlaWdodD0xMDAwfQ0KDQoNCg0KIyMjIDMuMiAqIlVuaXZhcmlhdGUiKiBhbmFsaXphICANClJhemR2YWphbW8gdXpvcmFrIG5hIHRyaSBwb2RncnVwZToNCmBgYHtyfQ0KI2tyZWlyYW0gdHJpIG5vdmUgdGFiZWxlIHNhIGtvamltYSBkYWxqZSByYWRpbQ0Kc21hbGwgPC0gY2xlYW5fYltWZWxpY2luYSA8PSAyLCBdDQptZWRpdW0gPC0gY2xlYW5fYltWZWxpY2luYSA9PSAzLCBdDQpsYXJnZSA8LSBjbGVhbl9iW1ZlbGljaW5hID09IDQsIF0NCiNicmlzZW0gcHJlb3N0YWxlIG1lZGp1a29yYWtlDQpybShjLCBOQlNfZGF0YSkNCmdjKCkNCmBgYA0KDQpQcnZvIMSHZW1vIGRldGFsam5vIGFuYWxpemlyYXRpICoqdmVsaWthIHByZWR1emVjYSoqIChwb2RhY2kgYGxhcmdlYCkgcG/EjWV2xaFpIG9kIHN2aWggZ29yZSBuYXZlZGVuaWgga29yYWthIHUgYW5hbGl6aSwgdGFrbyBkYSDEh2Ugb3ZhaiBkZW8gaW1hdGkgdHJpIHBvZGdydXBlLCB6YXZpc25vIG9kIHNhbWUgdmVsacSNaW5lIGR1xb5uaWthLiBTYW1pbSB0aW0gaSBrcmXEh2VtbyB1IGRldGFsam51IGFuYWxpenUgc2FkYS4uLiAgDQoNCjxoMyBzdHlsZT0iY29sb3I6cmVkOyI+VW5pdmFyaWF0ZSBhbmFsaXphIHZlbGlraWggcHJlZHV6ZcSHYTwvaDM+DQoNClBvdHJlYm5vIGplIHByZSBzdmVnYSByYXpkdm9qaXRpIHV6b3JhayBuYSB2YWxpZGFjaW9uaSBpIGVzdGltYWNpb25pLiBVIG5hY2VsdSBwcmF2aWxvIGplIGRhIHNlIHV6b3JhayBkZWxpIG5hIDcwOjMwIG5hIHN0cmFudSBlc3RpbWFjaWplLCBtZWRqdXRpbSB1a29saWtvIGt1YnVyaW1vIHNhIHBvZGFjaW1hIExlbWVzaG93IHUgc3ZvbSBba3Vyc3UgbyBsb2dpc3RpY2tvaiByZWdyZXNpamldKGh0dHBzOi8vd3d3LmNhbnZhcy5uZXQvYnJvd3NlL29zdS9jb3Vyc2VzL2FwcGxpZWQtbG9naXN0aWMtcmVncmVzc2lvbikgYXJndW1lbnR1amUgZGEgamUgbW5vZ28gYml0bmlqZSBkYSBpbWFtbyBrb21wbGV0bmlqaSB1em9yYWsgemEgZXN0aW1hY2lqdSwgdGFrbyBkYSBjZW1vIHNlIHZvZGl0aSBvdm9tIGxvZ2lrb20gaSB1IG5hc2VtIHNsdWNhanUuICANClBhLCBwb2NuaW1vLg0KYGBge3J9DQojaXpyYWN1bmFtIGJyb2ogcmVkb3ZhDQpicm9qLnJlZC5scmdlPC1ucm93KGxhcmdlKQ0KYnJvai5kaWZvbHRhLmxyZ2U8LXN1bShhcy5udW1lcmljKGxhcmdlJGRlZmF1bHQueT09MSkpDQpwcm9jZW5hdC5kaWZvbHRhPC1icm9qLmRpZm9sdGEubHJnZS9icm9qLnJlZC5scmdlDQpgYGANCkRha2xlIHUgbmFqYm9samVtIHNsdWNhanUsIG5lIHJhY3VuYWp1Y2kgbWlzc2luZyB2YWx1ZSBpbWFtbyBgciBicm9qLmRpZm9sdGEubHJnZWAgZGlmb2x0YSwgc3RvIG5hbSBkZWx1amUga2FvIGplZHZhIGRvdm9sam5vLCB1a29saWtvIGJpc21vIHphZHJ6YWxpIDMwJSBiaWxpIGJpc21vIG5hIGdyYW5pY2kuIE1lZGp1dGltIGRhIGJpc21vIHNlIG9zaWd1cmFsaSB6YWRyemFjZW1vIDc1JSwgdGltZSBvcGV0IGltYW1vIGRvdm9sam5vIGRpZm9sdGEgemEgdmFsaWRhY2lqdSAob2tvIDQwKSwgb3ZkZSBzYW0gc2Ugdm9kaW8gc2F2ZXRvbSBwcm9mZXNvcmEgTGVtZXNob3ctYSBrb2ppIGthemUgZGEgc2UgdSBvdm9qIHNpdHVhY2lqaSB1dmVrIHBva3VzYSB6YWRvdm9saml0aSAqdHJhaW5pbmcgc2FtcGxlKi4gUyBkcnVnZSBzdHJhbmUgcmFjaW8gbmVzb2x2ZW50bmloIHUgdWt1cG5pbSBkdXpuaWNpbWEgbW96ZSBpbWF0aSByYXpsaWNpdGUgdnJlZG5vc3RpLCB0ai4gbmUgcG9zdG9qaSBrb25zZW56dXMgdSBsaXRlcmF0dXJpIG8gb3ZvaiB2cmVkbm9zdGkuIE92ZGUgYmlyYW1vIGRhIHphZHJ6aW1vIHRyZW51dGFuIHJhY2lvIHUgdXpvcmt1IHRha28gZGEgY2VtbyB1emV0aSA3NSUgb2QgKHNvbHZlbnRuaWggaSBuZXNvbHZlbnRuaWgpIGR1em5pa2EgemFqZWRubyBpIHJhZGl0aSBlc3RpbWFjaWp1IG5hIG5qZW11LiBPdmltIHBvc3R1cGtvbSBzbW8gaXpiZWdsaSBwb3N0dXBhayBrYWxpYnJhY2lqZSBqZXIgc21vIHUgKnRyYWluaW5nKiB1em9ya3UgemFkcnphbGkgc3R2YXJudSBmcmVrdmVuY2lqdSBkZWZhdWx0YSwgY2l0YWosIHZlcm92YXRub2N1IGRlZm91bHRhLiBKZWRhbiBwcm9ibGVtIGtvamkgc2UgbW96ZSBwb3RlbmNpamFsbm8gamF2aXRpIGplIHZhbGlkbm9zdCBIb3NtZXLigJNMZW1lc2hvdyB0ZXN0YSBzYSA0MCBkaWZvbHRhLiANCg0KYGBge3J9DQpzZXQuc2VlZCg2MCkNCiN6Ym9nIHJlcHJvZHVrY2lqZQ0Kc2FtcGxlLmxyZyA8LQ0Kc2FtcGxlKGJyb2oucmVkLmxyZ2UsIHNpemUgPSByb3VuZCgwLjc1ICogYnJvai5yZWQubHJnZSwgMCkpDQpscmdlLnRyYWluaW5nIDwtIGxhcmdlW3NhbXBsZS5scmcsIF0NCmxyZ2UudGVzdCA8LSBsYXJnZVstc2FtcGxlLmxyZywgXQ0KYGBgDQoNCg0KIyMjIyoqVGVzdGlyYW5qZSByYWRuZSBoaXBvdGV6ZSwgZGlza3JpbWluYXRpdm5vc3RpLCBrb3JlbGFjaW9uZSBtYXRyaWNlKiogIA0KDQpKb3MgamVkbm9tIGNlbW8gcHJlZ2xlZGF0aSB2YXJpamFibGU6DQoNCmBgYHtyfQ0KI3JwaXZvdFRhYmxlKGxyZ2UudHJhaW5pbmcpDQpzdW1tYXJ5X3RhYmxlPC10KHNhcHBseShscmdlLnRyYWluaW5nWywxMTo0M10sbXkuc3VtbWFyeSxhcmc9VCkpDQp0cl9zdW1tYXJ5X3RhYmxlPC10KHN1bW1hcnlfdGFibGUpDQpmb3JtYXRSb3VuZCgNCiAgICAgICAgICAgIGRhdGF0YWJsZSgNCiAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5X3RhYmxlLGNhcHRpb24gPSAiVGFiZWxhIDMuOlN1bWFybmkgcHJpa2F6IiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSAnbm9uZScNCiAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgY29sdW1ucyA9IGNvbG5hbWVzKHN1bW1hcnlfdGFibGUpDQogICAgICAgICAgICkNCmBgYA0KDQpHZW5lcmFsbmEgcHJlcG9ydWthIGplIGRhIHNlIHJhZG5hIGhpcG90ZXphIHRlc3RpcmEgcHJlIHRyZXRtYW5hIG5lZG9zdGFqdcSHaWggdnJlZG5vc3RpIGJ1ZHXEh2kgZGEgxIdlIHNlIG5lZG9zdGFqdcSHZSB2cmVkbm9zdGkgcG9wdW5qYXZhdGkgdXNsb3ZubyBvZCBzdGFuamEgc29sdmVudG5vc3RpIGR1em5pa2EuIFNhbWltIHRpbSBvdmRlIGNlbW8ga2FvIHBydmkgdmlkIHNlbGVrY2lqZSBpc3BpdGF0aSByYWRudSBoaXBvdGV6dSBrYWtvIGtvbnRpbnVhbG5paCB0YWtvIGkga2F0ZWdvcmlja2loIHZhcmlqYWJsaS4gUG/EjWXEh2VtbyBzYSBrb250aW51YWxuaW1bXjNdIGkgYW5hbGl6dSByYWRpdGkgdSBwYXJ1IHNhIHByb3Zlcm9tIGRpc2tyaW1pbmF0aXZub3N0aSB2YXJpamFibGkuIEpvxaEgdSBUYWJlbGkgMyB2aWRpbW8gdmVsaWthIG9kc3R1cGFuamEgc3JlZG5qZSB2cmVkbm9zdGkgb2QgbWVkaWphbmUgaSB0cmltb3Zhbm9nIHByb3Nla2EsIGJ1ZHVjaSBkYSBqZSBwcm9zZWsga2FvIG1lcmEgY2VudHJhbG5lIHRlbmRlbmNpamUgb3NldGxqaXZhIG5hIGF1dGxhamVyZSBvZGx1Y3VqZW1vIHNlIGRhIHBvc21hdHJhbW8gbWVkaWphbnUgaSB0cmltb3ZhbiBwcm9zZWssIHNhbWltIHRpbSBtb2d1Y25vc3QgKnQgdGVzdGEqIG90cGFkYS4gRGFsamUsIHNsZWRlY2kgcHJlcG9ydWtlIGl6IGxpdGVyYXR1cmUgb3ZhaiBkZW8gYW5hbGl6ZSBvc2xvbml0aSBuYSBwb3NtYXRyYW5qZSBib3ggcGxvdG92YSBpIGJpY2UgZG9wdW5qZW4gZGlza3JpbWluYXRpdm5vbSBhbmFsaXpvbSBBVVJPQy1hLiBQcmkgdGVzdGlyYW5qdSBrb3JlbGFjaWphIHByYWcgc2VsZWtjaWplIHBvc3RhdmxqYW1vIG5hIDAuNSBpIG9kIGR2ZSBiaXJhbW8gb251IHZhcmlqYWJsdSBrb2phIGltYSB2ZWN1IGRpc2tyaW1pbmFjaW9udSBtb2MuIA0KDQpLb2Qga2F0ZWdvcmlja2loIHZhcmlqYWJsaSBwb3NtYXRyYWNlbW8gdGFiZWxlIGZyZWt2ZW5jaWphIHRhbW8gZ2RlIHRvIGJ1ZGUgaW1hbG8gc21pc2xhIGkgc3Byb3Zlc3RpIENoaS1zcXVhcmVkIHRlc3QuIE92b20gcHJpbGlrb20gcG90cmVibm8gamUgaSBwcmVncnVwaXNhdGkgb3ZlIHZhcmlqYWJsZSB0YWtvIGRhIGJ1ZHUgemFkb3ZvbGplbmkga3JpdGVyaWp1bWk6IA0KDQoqICAgYnJvaiAqZGlmb2x0YSogcG8ga2F0ZWdvcmlqaSBrYXRlZ29yaWNrZSB2YXJpamFibGUgbW9yYSBiaXRpIG1pbmltdW0gNQ0KKiAgIHVrdXBhbiBicm9qIGR1em5pa2EgcG8ga2F0ZWdvcmlqaSBrYXRlZ29yaWNrZSB2YXJpamFibGUgbW9yYSBiaXRpIHZlY2kgb2Qgc3RvDQoqICAgcHJhdmlsbyAxIHUgMTAsIHphIHN2YWtpaCAxMCBkaWZvbHRhIG1vxb5lbW8gZG9kYXRpIGplZG51IG9iamHFoW5qYXZhanXEh3UsIG92byBwcmF2aWxvIG5hbSBzbHV6aSBzYW1vIGthbyB2b2RpbGphDQoqICAgKmRlZmF1bHQgcmF0ZSogbW9yYSBiaXRpIHN0YXRpc3RpY2tpIHJhemxpY2l0IG9kICpkZWZhdWx0IHJhdGUqLWEgdWt1cG5vZyB1em9ya2EsIGluYWNlIHNlIHZyc2kgcHJlZ3J1cGFjaWphDQoqICAgaWFrbyBjZW1vIGlzcGl0YXRpIGhpcG90ZXp1IHNhZ2xlZGF2YW5qZW0gdGFiZWxhIGZyZWt2ZW5jaWphLCBwb3NsZWRuanUgcmVjIGNlIG5hbSBkYXRpIHNhbWkgbW9kZWwgaSBuamVnb3ZlICpwKiB2cmVkbm9zdGksIG9kbm9zbm8gKmxpa2VsaWhvb2QgcmF0aW8qIHRlc3QgICANCg0KUHJ2byBwcmVnbGVkYWptbyBzYW11IGRpc3RyaWJ1Y2lqdSBqb3MgamVkbm9tLCBtYWRhIHN1IG5la2Ugc3R2YXJpIHZlYyBqYXNuZSBpeiBUYWJlbGUgMyBoYWpkZSBpcGFrIGRhIHBvZ2xlZGFtby4gIA0KUHJ2byBrcmVpcmFtbyBmdW5rY2lqdSB6YSBwbG90aXJhbmplOiBxcSBwbG90YSwgYm94IHBsb3RhLCBwb3JlZGplbmphIGd1c3RpbmEgdmVyb3ZhdG5vY2UgKGtlcm5lbGEgZW1waXJpc2tpaCBkaXN0cmlidWNpamEgdmVyb3ZhdG5vY2UpIGkga29uYWNubyB6YSBwcm92ZXJ1IGRpc2tyaW1pbmFjaWplIFJPQyBrcml2ZS4NCmBgYHtyfQ0KI2RlbGltbyB1em9yYWsgbmEga29udGludWFsbmUgaSBrYXRlZ29yaWNrZQ0KbHJnZS50cmFpbmluZy5jb250aW51YWxuZTwtbHJnZS50cmFpbmluZ1ssYyg3LDYsMTEsMTM6NDMpXQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZTwtbHJnZS50cmFpbmluZ1ssYyg3LDgsOSwxMCwxMildDQpscmdlLnRlc3QuY29udGludWFsbmU8LWxyZ2UudGVzdFssYyg3LDYsMTEsMTM6NDMpXQ0KbHJnZS50ZXN0LmthdGVnb3JpY2tlPC1scmdlLnRlc3RbLGMoNyw4LDksMTAsMTIpXQ0KDQoNCnBsb3Rpbmc8LWZ1bmN0aW9uKGRhdGFmcmFtZSwgcHJlZGljdG9yX2NvbCwgZGVmYXVsdF9jb2x1bW5fY29sLG49Myl7DQogIA0KICAjdHJhbnNmb3JtYWNpamEgcG9kYXRha2EgDQogIGRhdGFmcmFtZT1hcy5kYXRhLmZyYW1lKGRhdGFmcmFtZSkNCiAgZGF0YTwtZGF0YS5mcmFtZShwcmVkaWN0b3I9ZGF0YWZyYW1lWyxwcmVkaWN0b3JfY29sXSwNCiAgICAgICAgICAgICAgICAgICBkZWZhdWx0X2NvbHVtbj1mYWN0b3IoZGF0YWZyYW1lWyxkZWZhdWx0X2NvbHVtbl9jb2xdKSkNCiAgZGF0YTwtbmEub21pdChkYXRhKQ0KICANCiNkZW5zaXR5IHBsb3QjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgZGVuc2l0eTwtZ2dwbG90KGRhdGEsIGFlcyhwcmVkaWN0b3IsIGZpbGw9ZmFjdG9yKCBkZWZhdWx0X2NvbHVtbikpKSArIA0KICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyM5OTk5OTknLCcjRTY5RjAwJykpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikreGxpbShxdWFudGlsZShkYXRhJHByZWRpY3RvcixjKDAuMDUsMC45NSksbmEucm0gPSBUKSkNCg0KI2JveHBsb3QjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpib3hfcGxvdDwtZ2dwbG90KGRhdGEsIGFlcyh5PXByZWRpY3RvciwgeD0gZGVmYXVsdF9jb2x1bW4sIGZpbGw9ZGVmYXVsdF9jb2x1bW4pKSsNCiAgZ2VvbV9ib3hwbG90KGFscGhhPTAuNSkNCiAgIyBjb21wdXRlIGxvd2VyIGFuZCB1cHBlciB3aGlza2Vycw0KeWxpbTEgPSBib3hwbG90LnN0YXRzKGRhdGEkcHJlZGljdG9yKSRzdGF0c1tjKDEsIDUpXQ0KICAjIHNjYWxlIHkgbGltaXRzIGJhc2VkIG9uIHlsaW0xDQpib3hfcGxvdCA9IGJveF9wbG90ICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSB5bGltMSpuKSsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyM5OTk5OTknLCcjRTY5RjAwJykpDQoNCiNyb2MgY3VydmUgcGxvdCMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpST0NfcGxvdCA8LQ0KICBnZ3Bsb3QoZGF0YSwgYWVzKG0gPSBwcmVkaWN0b3IsIGQgPSBhcy5udW1lcmljKGRlZmF1bHRfY29sdW1uKSkpICsgZ2VvbV9yb2MoKSArDQogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsDQogICAgICAgICAgICAgIHNsb3BlID0gMSwNCiAgICAgICAgICAgICAgY29sb3IgPSAncmVkJykNCg0KcmVzdWx0IDwtIGF1YyhkYXRhJGRlZmF1bHRfY29sdW1uLCBkYXRhJHByZWRpY3RvcikNCg0KYSA9IHBhc3RlKCJBcmVhIHVuZGVyIHRoZSBjdXJ2ZToiLA0KICAgICAgICAgIHJvdW5kKGNpKHJlc3VsdClbWzFdXSwgMyksDQogICAgICAgICAgIiwgIiwNCiAgICAgICAgICByb3VuZChyZXN1bHQsIDMpLA0KICAgICAgICAgICIsICIsDQogICAgICAgICAgcm91bmQoY2kocmVzdWx0KVtbM11dLCAzKSkNCg0KUk9DX3Bsb3QgPC0gUk9DX3Bsb3QgKyBsYWJzKHRpdGxlID0gYSkNCg0KI1FRIHBsb3QNCg0KcXMgPSBzZXEoMC4wMDEsIDAuOTk5LCBieT0wLjAwMSkNCmRmLnFzID0gZGF0YS5mcmFtZShxdWFudGlsZS5QID0gcXMsDQogICAgICAgICAgICAgICAgICAgcS52YWwuTm9ybWFsID0gcW5vcm0ocXMsbWVhbihkYXRhJHByZWRpY3Rvciksc2QoZGF0YSRwcmVkaWN0b3IpKSwNCiAgICAgICAgICAgICAgICAgICBxLnZhbC5YID0gcXVhbnRpbGUoZGF0YSRwcmVkaWN0b3IscXMpKQ0KUVFfcGxvdD1nZ3Bsb3QoZGYucXMsIGFlcyhxLnZhbC5Ob3JtYWwsIHEudmFsLlgpKSsNCiAgZ2VvbV9wb2ludChjb2w9JyM5OTk5OTknLCBjZXg9MikrDQogIGdlb21fbGluZShjb2w9JyM5OTk5OTknLCBzaXplPTAuNzUpKw0KICBnZW9tX2FibGluZShwb3NpdGlvbj0iaWRlbnRpdHkiKQ0KDQpwbG90X2dyaWQoZGVuc2l0eSxib3hfcGxvdCxST0NfcGxvdCxRUV9wbG90LGFsaWduID0gImgiLCBuY29sID0gNCkNCg0KfQ0KDQoNCmBgYA0KDQojIyMjS3JlxIdlbW8gc2Egb3Bpc29tIHN2YWtlIHZhcmlqYWJsZSBwb25hb3NvYjoNCiMjTmVwcmVraWRuZSBwcm9tZW5saml2ZToNCiMjIyNVZGVvIGlzcHJhdmtlIHUgdWt1cG5pbSBrcmVkaXRpbWEgIA0KX19fX19fX19fX19fX19fX19fX19fXw0KDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZyw2LDcpDQoNCmBgYA0KVmlkaW1vIGRhIGRpc3RyaWJ1Y2lqZSBvZHN0dXBhanUgZGFsZWtvIG9kIG5vcm1hbG5lLCBkYWxqZSBwcmVrbGFwYW5qZSBkaXN0cmlidWNpamEgc29sdmVudG5paCB1IG5lc29sdmVudG5paCBkdXpuaWthIGplIHJhem9jYXJhdmFqdWNlLCBwb3N0b2ppIDcgYXV0bGFqZXJhIGtvamkgaW1hanUgbmVsb2dpY25lIHZyZWRub3N0aSBrb2ppIHZ1a3UgcG9yZWtsbyBpeiByayBvYnJhc2NhLiBJYWtvIGJveCBwbG90IHBva2F6dWplIG9kcmVkamVuaSBzdGVwZW4gZGlza3JpbWluYWNpamUgdSBzbWlzbHUgZGEgc3Ugc29sdmVudG5pIGR1em5pY2kgbWFuamUgaXNwcmF2bGplbmkgb2QgbmVzb2x2ZW50bmloLCBnZW5lcmFsbm8gUk9DIGtyaXZhIHBva2F6dWplIGRhIGplIGRpc2tyaW1pbmFjaWphIG1hcmdpbmFsbmEgaWFrbyBqZSB6bmFjYWpuYSBuYSBuaXZvdSBwb3ZlcmVuYWogb2QgOTUlLCBpcGFrLCB6bmFjYWpub3N0IGplIG1hcmdpbmFsbmEuIEF1dGxhamVyaSBpbWEgaWgsIGltYSBpaCBtbm9nby4gQnVkdWNpIGRhIGNlIHNsaWNubyBiaXRpIGkgc2Egb3N0YWxpbSB2YXJpamFibGFtYSBrcmVpcmFtbyB0YWtzYXRpdmFuIG9waXMgdSB2aWR1IGJ1bGV0YSB6YSBzdmFrdSB2YXJpamFibHUga2FvIHN0byBzbGVkaSB6YSBvdnU6ICANCg0KKiAgIFJhZG5hIGhpcG90ZXphLW5pc21vIHBvc3RhdmlsaSByYWRudSBoaXBvdGV6dSB6YSBvdnUgdmFyaWphYmx1DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLW5lIHBvc3RvamkgbmEgOTUlIHNpZ3Vybm9zdGkgDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWggaW1hDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQogDQogIA0KIyMjI0Jyb2ogemFwb3NsZW5paCAgDQpfX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDExLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLW5pc21vIHBvc3RhdmlsaSByYWRudSBoaXBvdGV6dSB6YSBvdnUgdmFyaWphYmx1DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hIGplIA0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNSaWdvcm96bmkgcmFjaW8gcmVkdWtvdmFuZSAobW9uZXRhcm5lKSBsaWt2aWRub3N0aSAgDQpfX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDEzLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aSANCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLiAgDQoNCiMjIyNSYWNpbyBub3ZjYW5lIGxpa3ZpZG5vc3RpIChDYXNoX3JhdGlvKSAgDQpfX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMTQsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgbmEgOTUlIHpuYWNham5vc3RpICBpIG9iZWNhdmEhISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLiAgDQoNCg0KDQojIyMjT3BzdGkgcmFjaW8gbGlrdmlkbm9zdGkgIA0KX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE1LDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLW5lemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5lbWEgbmEgOTUlIHpuYWNham5vc3RpICBpIHRvIHRpIGplISEhDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4gIA0KDQojIyMjU3RlcGVuX3phZHV6ZW5vc3RpICANCl9fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE2LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGkhISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjSW50ZXJlc3QgQ292ZXJhZ2UgUmF0aW8gIA0KX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE3LDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aSAgaSBvayBqZSwgbW96ZSBkYSBwcm9kamUsIG1hZGEga3JpdnVkYSBzdG8gbmlqZSBkb2JybyEhIQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLCBhbGkgYmFyIGxpY2kgbmEgbmVzdG8gbm9ybWFsbm8uLi4NCg0KIyMjI1JhY2lvIHBva3JpY2Egb2JydG5lIGltb3ZpbmUgIA0KX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE4LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgbmEgOTUlIHpuYWNham5vc3RpICBpIG9rIGplLCBzb2xpZG5vISEhDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEgDQoNCiMjIyNSYWNpbyBvYnJ0YSBwb3RyYXppdmFuamEgb2Qga3VwYWNhICANCl9fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE5LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hIGplIDk1JSB6bmFjYWpub3N0aQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLCB2aXNlIGthbyAkXHRpbGRlXGNoaV4yJG5vc3QgaGloaWhpLCBrYXBpcmFzIGhpIGthbyBoaSBkaXN0cmlidWNpamEgOikgLi4uIA0KDQojIyMjUmFjaW8gb2JydGEgcG9zbG92bmUgaW1vdmluZSAgDQpfX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyMCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIG1hbmppaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGkgIGkgb2sgamUsIG1vemUgZGEgcHJvZGplLCBtYWRhIGtyaXZ1ZGEgc3RvIG5pamUgZG9icm8hISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjR290b3ZpbnNraSBjaWtsdXMgMSAgDQpfX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyMSw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aSwgemFzdG8gcGl0YW0gc2UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGkgIGkgb2sgamUsIG1vemUgZGEgcHJvZGplLCBtYWRhIGtyaXZ1ZGEgc3RvIG5pamUgZG9icm8hISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjVnJlbWUgdmV6aXZhbmphIHphbGloYSAgDQpfX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMjIsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5lbWEgbmEgOTUlIHpuYWNham5vc3RpDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI1ZyZW1lIGtyZWRpdGlyYW5qYSBrdXBhY2EgIA0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDIzLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgdmVjaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hIG5hIDk1JSB6bmFjYWpub3N0aQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNWcmVtZSBuYXBsYXRlIHBvdHJhxb5pdmFuamEgIA0KX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyNCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIHZlY2loIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNWcmVtZSBwbGHEh2FuamEgZG9iYXZsamHEjWltYSAgDQpfX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDI1LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtbmV6YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIG1hbmppaCB2cmVkbm9zdGksIGlwYWsgY2VtbyBqZSB1emV0aSwgamVyIG1vxb5lIGVrb25vbXNraSBkYSBzZSBvYmphc25pIHJlenVsdGF0DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgbmEgOTUlIHpuYWNham5vc3RpIHN1cHJvdGFuIHpuYWssIG9ubyBzdG8gYmkgbW9nbG8gcHJhdml0aSBwcm9ibGVtIGplIHByb21lbmEgZGlza3JpbWluYXRpdm5vc3RpIGtvZCBwb3NsZWRuamUgY2V0dnJ0aW5lIGRpc3RyaWJ1Y2lqZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNBc3NldCB0dXJub3Zlcg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDI2LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2EgdmVyb3ZhdG5vY2EgZGlmb2x0YSBrb2QgbWFuamUgbWVkaWphbmUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5lbWEgbmEgOTUlIHpuYWNham5vc3RpLCBpcGFrIGNlbW8gamUgdXpldGksIHpib2cgZGlza3JpbWluYXRpdm5vc3RpIHUgbWFuamltIHZyZWRub3N0aW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KDQojIyMjUmFzdCBFQklUREENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyNyw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjYSB2ZXJvdmF0bm9jYSBkaWZvbHRhIGtvZCBtYW5qZSBtZWRpamFuZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gbmEgZ3JhbmljaSBuYSA5NSUgem5hY2Fqbm9zdGksIHV6ZWNlbW8sIG1hZGEgbWVuamEgZGlza3JpbWluYXRpdm5vc3QsIHZpZGVjZW1vIHBvc2xlIG11bHRpdmFyaWF0YQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNTdG9wYSBwcmlub3NhIG5hIHNvcHN0dmVuaSBrYXBpdGFsIHByZSBvcG9yZXppdmFuamENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyOCw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLW5lIHpuYW0ga29qaSBtdSBqZSBkamF2byBhbGkgZXZvIG92ZGUgY2VtbyBtZWRpamFuYSB6ZHJhdm9nIGplIGByIG1lZGlhbihhcy5tYXRyaXgobHJnZS50cmFpbmluZ1tkZWZhdWx0Lnk9PTAsMjhdKSxuYS5ybT1UKWAgYSBuZXNvbHZlbnRub2cgamUgYHIgbWVkaWFuKGFzLm1hdHJpeChscmdlLnRyYWluaW5nW2RlZmF1bHQueT09MSwyOF0pLG5hLnJtPVQpYCBzdG8gb2Rnb3ZhcmEgcmFkbm9qIGhpcG90ZXppDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSB6bmFjYWpubyBuYSA5NSUgem5hY2Fqbm9zdGksIHV6ZWNlbW8NCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjU3RvcGEgcHJpbm9zYSBuYSB1a3VwbmEgc3JlZHN0dmEgcHJlIG9wb3Jleml2YW5qYQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDI5LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtbmUgem5hbSBrb2ppIG11IGplIGRqYXZvIGFsaSBldm8gb3ZkZSBjZW1vIG1lZGlqYW5hIHpkcmF2b2cgamUgYHIgbWVkaWFuKGFzLm1hdHJpeChscmdlLnRyYWluaW5nW2RlZmF1bHQueT09MCwyOV0pLG5hLnJtPVQpYCBhIG5lc29sdmVudG5vZyBqZSBgciBtZWRpYW4oYXMubWF0cml4KGxyZ2UudHJhaW5pbmdbZGVmYXVsdC55PT0xLDI5XSksbmEucm09VClgIHN0byBvZGdvdmFyYSByYWRub2ogaGlwb3RlemkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIHpuYWNham5vIG5hIDk1JSB6bmFjYWpub3N0aSwgbXVhDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gamVkYW4gb2QgYmxpemloLi4uDQoNCiMjIyNCYXNpYyBFYXJuaW5ncyBQb3dlciBSYXRpbw0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDMwLDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUsIHZlY2kgZGlmb2x0IHNhIG1hbmpvbSB2cmVkbm9zY3UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGksIG11YQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1Jhc3QgcHJpaG9kYSBvZCBwcm9kYWplDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzEsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hIGplLCBuZW1hIHZpZGxqaXZlIHJhemxpa2UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5pamUgem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpLCBrYW5kaWRhdCB6YSBrYXRlZ29yaWNrdQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1Bva3JpxIdlIG5ldG8ga2FtYXRhDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzIsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUgbWFkYSBuZW1hIHZpZGxqaXZlIHJhemxpa2UgemJvZyBhdXRsYWplcmENCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5pamUgem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpLCBtZWRqdXRpbSBST0MgaW1hIHMgb2JsaWsgc3RvIHpuYWNpIGRhIHBvc3RvamkgZGlza3JpbWluYXRpdm5vc3Qgb2JybnV0b2cgc21lcmEgbmEgdmVjaW0gaSBtYW5qaW0gdnJlZG5vc3RpbWEsIG1lZGp1dGltIG92byB6bmFjaSBpIGRhIG9kbm9zIHNhIHZlcm92YXRub2NvbSBkZWZhdWx0LWEgbmlqZSBtb25vdG9uLCBrYW5kaWRhdCB6YSBrYXRlZ29yaWNrdQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI0NlbmEgdHXEkWloIGl6dm9yYSBzcmVkc3RhdmENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywzMyw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZSwgbmVtYSB2aWRsaml2ZSByYXpsaWtlDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuaWplIHpuYWNham5hIG5hIDk1JSB6bmFjYWpub3N0aSwgbWVkanV0aW0gUk9DIGltYSBzIG9ibGlrIHN0byB6bmFjaSBkYSBwb3N0b2ppIGRpc2tyaW1pbmF0aXZub3N0IG9icm51dG9nIHNtZXJhIG5hIHZlY2ltIGkgbWFuamltIHZyZWRub3N0aW1hLCBtZWRqdXRpbSBvdm8gem5hY2kgaSBkYSBvZG5vcyBzYSB2ZXJvdmF0bm9jb20gZGVmYXVsdC1hIG5pamUgbW9ub3Rvbg0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KDQojIyMjVDENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywzNCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpLCBtZWRqdXRpbSBicmluZSBtb25vdG9ub3N0LCBtb3plIGRhIHByb2RqZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1QyDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzUsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjVDMNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywzNiw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hIGplDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSB6bmFjYWpuYSBuYSA5NSUgem5hY2Fqbm9zdGkNCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBqb29rLi4uDQoNCg0KIyMjI1Q0DQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzcsNykNCg0KYGBgDQoNCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hIGplDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBtYXN0ZXJwaWVjZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1Q1DQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzgsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gbmVtYQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1QyMQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDM5LDcpDQoNCmBgYA0KDQoNCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hLCB6YSBtYWxvDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjQWx0bWFuIFotc2NvcmUgMQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDQwLDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG1hc3RlcnBpZWNlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCiMjIyNBbHRtYW4gWi1zY29yZSAyDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsNDEsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG1hc3RlcnBpZWNlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCiMjIyNBbHRtYW4gWi1zY29yZSAzDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsNDIsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG1hc3RlcnBpZWNlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCg0KIyMjI1VkZW8gdSBrYXBpdGFsdSBiYW5rZQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDQzLDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUsIHZlY2kgdWRlbyBsb3Npamkgc3UgdSBwcm9zZWt1DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSB6YSB2ZWNlIHZyZWRub3N0aSBkYQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4gIA0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCg0KIyMjS29yZWxhY2lvbmEgbWF0cmljYSAgDQoNCkthbyBkb2RhdG5pIGtyaXRlcmlqdW0gc2VsZWtjaWplIHV6aW1hbW8gaSBrb3JlbGFjaW9udSBtYXRyaWN1LiBWb2RpY2VtbyBzZSBwcmUgc3ZlZ2EgZGlza3JpbWluYXRpdm5vbSBtb2NpIGtvanUgcG9zbWF0cmFtbyBwcmVtYSBBVVJPQyB2cmVkbm9zdGkga2FvIHBydmltIGtyaXRlcmlqdW1vbSBwcmkgaXpib3J1IGl6bWVkanUgZHZlIHZhcmlqYWJsZSBzYSB2ZWxpa2ltIHN0ZXBlbm9tIGtvcmVsYWNpamUuICANClUgdGFiZWxpIDUuIGlzcG9kIHZpZGltbyBkYSBuYWp2ZWN1IGRpc2tyaW1pbmFjaW9udSBtb2MgcG9zZWR1amUgdmFyaWphYmxhIFQxNCBvZG1haCBpemEga29qZSBqZSBBTHRtYW4gMS4gDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9DQojcHJvcmFjdW4NCmNvcj1jb3IobHJnZS50cmFpbmluZy5jb250aW51YWxuZVssYygtMSwtMzEsLTMyLC0zMyldLCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KI2RvZGFqZW1vIEFVUk9DIGthbyBkb2RhdG51IGtvbG9udSBwb3JlZCB2YXJpamFibGUNCg0KY29ycl9zdW1tYXJ5PC1mdW5jdGlvbiAocHJlZGljdG9yKXsNCiAgcmVzcG9uc2U9ZmFjdG9yKGxyZ2UudHJhaW5pbmcuY29udGludWFsbmVbWzFdXSkNCnN1cHByZXNzTWVzc2FnZXMoYXVjKHJlc3BvbnNlLCBhcy5udW1lcmljKHByZWRpY3RvcikpKQ0KfQ0KDQphdWNfc3VtYXJubzwtc2FwcGx5KGxyZ2UudHJhaW5pbmcuY29udGludWFsbmVbLGMoLTEsLTMxLC0zMiwtMzMpXSwgY29ycl9zdW1tYXJ5KQ0Ka29yX2Rpc2tyPC0oY2JpbmQoYXVjX3N1bWFybm8sY29yKSkgDQoNCmZvcm1hdFJvdW5kKA0KICAgICAgICAgICAgZGF0YXRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgIGtvcl9kaXNrcixjYXB0aW9uID0gIlRhYmVsYSA1LjpTdW1hcm5pIHByaWtheiIsDQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gJ25vbmUnDQogICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgIGNvbHVtbnMgPSBjb2xuYW1lcyhrb3JfZGlza3IpDQogICAgICAgICAgICkNCg0KYGBgDQoNCk92ZGUga3JlaXJhbSBmdW5rY2lqdSBrb2phIGNlIGRhIGZpbHRyaXJhIHZhcmlqYWJsZSBwbyBrcml0ZXJpanVtdSBrb3JlbGFjaWplLiBOYWltZSwgcG8gdWdsZWR1IG5hIFteNF0ga2FvIGtyaXRlcmlqdW0gZ3JhbmljZSBrb2VmaWNpamVudGEga29yZWxhY2lqZSBwcmVrbyBrb2plIG5lIGJpc21vIHNtZWxpIHByZWxheml0aSB1emVjZW1vIHZyZWRub3N0IG9kIDAuNSBrb2ppIGNlIHUgc3ByZXppIHNhIEFVUk9DIHZyZWRub3N0aSBzZWxla3RpcmF0aSBqZWRudSBvZCBkdmUgdmFyaWphYmxlLiBLb25hY2FuIGl6Ym9yIHZhcmlqYWJsaSBzZSB2aWRpIHUga29yZWxhY2lvbm9qIHRhYmVsaSBpc3BvZC4gIA0KDQpgYGB7cn0NCiNhc3N1bWluZyB0aGF0IHRhYmxlIGlzIG4geCAobisxKSBtYXRyaXggd2hlcmUgZmlyc3QgY29sdW1uIGlzIEFVUk9DIHZhbHVlIGFuZCB0aGUgcmVzdCBuIHggbiBpcyBjb3JyZWxhdGlvbiBtYXRyaXggDQpjb3JyX2VsbGltaW5hdGlvbjwtZnVuY3Rpb24odGFibGUxLCBybz0wLjUpew0KICB0YWJsZT10YWJsZTENCiAgQVVST0M8LXRhYmxlWywxXQ0KICB0YWJsZTwtdGFibGVbb3JkZXIodGFibGVbLDFdLGRlY3JlYXNpbmcgPSBUKSxdWywtMV0NCiAgdGFibGUudGVtcD1hcy5kYXRhLmZyYW1lKHRhYmxlKQ0KICBmb3IoaSBpbiAxOm5jb2wodGFibGUpKXsja29sb25hDQogICAgZm9yKGogaW4gMTpucm93KHRhYmxlKSl7I3JlZA0KICAgICAgI2Jyb3dzZXIoKQ0KICAgICAgaWYoYWJzKHRhYmxlW2ksal0pPnJvICYgYWJzKHRhYmxlW2ksal0pPDEpew0KICAgICAgICByb3cubmFtZT1yb3duYW1lcyh0YWJsZSlbaV0NCiAgICAgICAgaWYoc3VtKHJvdy5uYW1lPT1jb2xuYW1lcyh0YWJsZS50ZW1wKSk9PTApIG5leHQNCiAgICAgICAgY29sLm5hbWU9Y29sbmFtZXModGFibGUpW2pdDQogICAgICAgIHRhYmxlLnRlbXA9dGFibGUudGVtcFssY29sLm5hbWUhPWNvbG5hbWVzKHRhYmxlLnRlbXApXQ0KICAgICAgICB0YWJsZS50ZW1wPXRhYmxlLnRlbXBbY29sLm5hbWUhPXJvdy5uYW1lcyh0YWJsZS50ZW1wKSxdDQogICAgICB9DQogICAgfQ0KICB9DQogIA0KICBBVVJPQz1BVVJPQ1tyb3duYW1lcyh0YWJsZS50ZW1wKV0NCiAgDQogIHRhYmxlLnRlbXA9Y2JpbmQoQVVST0MsdGFibGUudGVtcCkNCiAgdGFibGUudGVtcDwtdGFibGUudGVtcFtBVVJPQz4wLjU1LF0NCiAgdGFibGUudGVtcDwtdGFibGUudGVtcFsscm93bmFtZXModGFibGUudGVtcCldDQogIA0KICB0YWJsZS50ZW1wW29yZGVyKHJvd25hbWVzKHRhYmxlLnRlbXApKSxvcmRlcihjb2xuYW1lcyh0YWJsZS50ZW1wKSldDQogIEFVUk9DPUFVUk9DW3Jvd25hbWVzKHRhYmxlLnRlbXApXQ0KICB0YWJsZS50ZW1wPWNiaW5kKEFVUk9DLHRhYmxlLnRlbXApDQoNCn0NCg0KY2xlYW5fY29yPC1jb3JyX2VsbGltaW5hdGlvbihrb3JfZGlza3IpDQprbml0cjo6a2FibGUoY2xlYW5fY29yLCBjYXB0aW9uID0gIlRhYmVsYSA2LiBza3JhY2VuYSBrb3JlbGFjaW9uYSB0YWJlbGEga29qYSBzYWRyemkgdmFyaWphYmxlIG5hZCBrb2ppbWEgY2Ugc2UgdnJzaXRpIGRhbGphIGFuYWxpemEiKQ0KDQpgYGANCg0KRGEgc3VtaXJhbW8sIGRvIHNhZGEgc21vIGtvZCBrb250aW51YWxuaWgsIHByZWdsZWRhbGkgZGlza3JpbWluYXRpdm5vc3QuIEdlbmVyYWxubyBbXjRdIHByZXBvcnVjdWplIGRhIHNlIG9kcmFkaSAqdW5pdmFyaWF0ZSogbG9naXN0aWNrYSBwYSBuamVuYSBkaXNrcmltaW5hdGl2bm9zdCB0ZXN0aXJhLiBNZWRqdXRpbSBvdmRlIHNtbyBwcmF0aWxpIFteNV0gZ2RlIHNtbyBwb3NtYXRyYWxpIGRpc2tyaW1pbmF0aXZub3N0IHNhbWloIHZhcmlqYWJsaS4gRGFsamUsIHBvc3RvamkgcGFyIHZhcmlqYWJsaSBrb2plIGJpc21vIG1vZ2xpIGRhIHRyYW5zZm9ybWlzZW1vIHUga2F0ZWdvcmlja2UsIHN0byBqZSBwb3plbGpuby4gIA0KDQpPc2ltIHRlc3RpcmFuamEgbW9ub3Rvbm9zdGkgaGlwb3RlemUsIG5lZ2RlIHNlIHRlc3RpcmEgaSBwb3N0b2phbmplIGxpbmVhcm5lIHphdmlzbm9zdCBpem1lZGp1IGxvZ2FyaXRtYSBlbXBpcmlqc2tpaCBzYW5zaSBpIHZhcmlqYWJsaVteNF0gaSBpc3RvdnJlbWVubyBzZSB0cmFuc2Zvcm1pc3UgdmFyaWphYmxlLiBbXjZdIHByaWthenVqdSBwb3N0dXBhayB0cmFuc2Zvcm1hY2lqZSBhbGkgaSB1cG96b3JhdmFqdSBuYSBvcGFzbm9zdCBvZCAqZGF0YS5taW5pbmcqLWEsIFteNV0gaSBbXjRdIHRha29kamUgcHJpbWVuanVqdSBpc3RvdmV0YW4gcG9zdHVwYWsuIE1pIGNlbW8gb3ZkZSBrb3Jpc3RpdGkgcG9zdHVwYWsgb3Bpc2FuIHUgW142XSB6YSBwYXIgdmFyaWphYmxpIGtvamUgbmlzdSBwb2themFsZSBtb25vdG9udSB6YXZpc25vc3Qgc2EgaGlwb3Rlem9tLCB1a29saWtvIG51emRhIG5hdGVyYSwgYWxpIHNhbW8gdGFkYSwgdHJhbnNmb3JtaXNhY2VtbyBzdmUga29udGludWFsbmUgdmFyaWphYmxlLiBaYSBzYWRhIGNlbW8gb3ZhaiBwb3N0dXBhayBwcmltZW5pdGkgbmEgdmFyaWphYmxhbWEgKlBva3JpxIdlIG5ldG8ga2FtYXRhLCBBc3NldCB0dXJub3ZlciouIFZhcmlqYWJsYSBrb2p1IGNlbW8gcHJldHZvcml0aSB1IGthdGVnb3JpY2t1IGplICpVZGVvIHUga2FwaXRhbHUgYmFua2UqLiBEaW5hbWlja2UgdmFyaWphYmxlICpSYXN0IEVCSVREQSBpIFJhY2lvIG9icnRhIHBvc2xvdm5lIGltb3ZpbmUqIG5lbWFqdSBuZWt1IHByZXZpc2Ugem5hY2FqbnUgZGlza3JpbWluYXRpdm51IG1vYyBkYSBiaSBzZSBvcHJhdmRhbG8gc2tyYWNlbmplIGNpdGF2ZSBzZXJpamUgdXpvcmthLCB0YWtvIGRhIGNlIHNlIHRyZXRpcmF0aSBrYW8gZGEgc3Ugb3RwYWxlIHUgKnVuaXZhcmlhdGUgYW5hbHlzaXMqIHVzbGVkIHZlbGlrb2cgYnJvamEgbmVkb3N0YWp1Y2loIHZyZWRub3N0aS4gTmFwcmF2aWNlbW8gamVkYW4gaXp1emV0YWsga2FkYSBidWRlbW8gcHJpbWVuaWxpIHByYXZpbG8gb2RzdHJhbmppdmFuamEgdmFyaWphYmxpIHVzbGVkIG5lZG9zdGFqdWNpaCB2cmVkbm9zdGksIGEgdG8gamUgdmFyaWphYmxhIGtvamEgamUgbmEgZ3JhbmljaSwgKkNhc2hfcmF0aW8qIGplciBqZSBwb2themFsYSB2ZWxpa3UgZGlza3JpbWFjaW9udSBtb2MuIERpc2tyaW1pbmFjaW9udSBtb2MgZ2xlZGFtbyBwbyB6bmFjYWpub3N0aSBpbnRlcnZhbGEgcG92ZXJlbmphIG9kIDk1JSwga29qaSBzZSBrb2QgZnVua2NpamUgdSBSLXUgcmFjdW5hIGJvb3RzdHJhcG92YW5qZW0uIEdlbmVyYWxubywgdnJlZG5vc3RpIEFVUk9DLWEgdSB2ZWNpbSB1em9yY2ltYSBrb2plIGltYWp1IHZyZWRub3N0aSB2ZWNlIG9kIDU1IHNlIG1vZ3Ugc21hdHJhdGkgem5hY2FqbmltLiAgDQoNClBhIGhhamRlIGRhIGtyZW5lbW8gc2EgZ29yZSBuYXZlZGVuaW0uIFRha29kamUsIHZpZGVoIGRhIGplIG1vemRhIGJyb2ogemFwb3NsZW5paCBiaWxvIHBvdHJlYm5vIHJ0YWN1bmF0aSBwcmVtYSBha3Rpdmkga2FvIHJhY2lvLCBhbGkgdG8gbWkgIHJhbmlqZSBuaWplIHBhbG8gbmEgcGFtZXQsIG1hZGEgbmUgbWlzbGltIGRhIGJpIGltYWxvIHpuYWNham5paCBwcm9tZW5hLCBldmVudHVhbG5vLCB2YXJpamFibGEga29qYSBiaSBpbWFsYSBzbWlzbGEgamUgcHJvY2VudHVhbG5hIHByb21lbmEgb3ZlIHZhcmlqYWJsZSwgxaF0byBiaSwgb3BldCwgemFodGV2YWxvIGd1YmxqZW5qZSBwcnZlIGdvZGluZSBvYnNlcnZhY2lqYSBzYW1vIHpib2cgbmplLCBqZXIgc2UgZHJ1Z2UgZGluYW1pY2tlIHZhcmlqYWJsZSBuaXN1IHBva2F6YWxlIGthbyBkb3ZvbGpubyBkaXNrcmltaW5hdGl2bm8gem5hY2FqbmUuICANCg0KRG9kYXRubyBvIGRpbmFtaWNraW0gdmFyaWphYmxhbWEsIHUgYnVkdWNpbSB2ZXpiYW1hLCBwcmVkbGF6ZW0gZGEgc2Ugc2tyb3ogaXpiYWNlIGl6IHNlbGVrY2lqZSBpeiByYXpsb2dhIHN0byBuaXN1IG1vbm90b25lLCBuYWltZSwgYnVkdWNpIGRhIG92ZSB2YXJpamFibGUgbW9ndSB1emltYXRpIGtha28gbmVnYXRpdm5lIHRha28gaSBwb3ppdGl2bmUgdnJlZG5vc3RpLiBQcmltZXJhIHJhZGksIG1vZ3VjIGplIHNsZWRlY2kgc2x1Y2FqLCByZWNpbW8gZGEgaW1hbW8gZHZhIHByZWR1emVjYSAkWF57WzFdfSQgaSAkWF57WzJdfSQsIHUgcm9rdSBvZCBkdmUgZ29kaW5lIG9uaSBzdSBvc3R2YXJpbGkgc2xlZGVjZSB2cmVkbm9zdGkgbmVrb2cgcmFjaWphIGtvamkgamUgb2JybnV0byBwb3ZlemFuIHNhIGRpZm9sdG9tICh2ZWNpIHJhY2lvLW1hbmppIFBEKTogIA0KJCQgdDpYX3t0fV57WzFdfT0tMC41LCBYX3t0fV57WzJdfT0wLjcgXFwgdCsxOlhfe3QrMX1ee1sxXX09LTAuOSwgWF97dCsxfV57WzJdfT0wLjkgJCQgIA0KVGFrbyBkYSB1a29saWtvIHNhZGEgaXpyYWN1bmFtbyByYXN0IG92b2cgcmFjaWphIHphIG9iYSBwcmVkdXplY2EgZG9iaWphbW86ICANCiQkUl97eF57WzFdfX09XGZyYWN7WF97dCsxfV57WzFdfX17WF97dH1ee1sxXX19LTE9ODAgXCVcXCBSX3t4XntbMl19fT1cZnJhY3tYX3t0KzF9XntbMl19fXtYX3t0fV57WzJdfX0tMT0yOFwlICQkDQoNCiwgc3RvIGJpIHpuYWNpbG8gZGEgcHJlZHV6ZWNlIDEgaW1hIGJvbGppIFBEIG9kIHByZWR1emVjYSAyIHBvIHBvY2V0bm9qIGhpcG90ZXppLCBhIHRvIG5lIG1vemUgYml0aSBqZXIgamUgcG96aWNpamEgcHJlZHV6ZWNhIDEgb2Qgc3RhcnRhIGJpbGEgbG9zaWphIGkgam9zIHNlIHBvZ29yc2FsYSB1IHNsZWRlY2loIGdvZGludSBkYW5hLiBPdm8gamUgZ2xhdm5pIHJhemxvZyB6Ym9nIGtvZ2EsIHZlcm92YXRubywgb3Zha3ZlIHZhcmlqYWJsZSBuaXN1IHBva2F6YWxlIGpha3UgZGlza3JpbWluYXRpdm51IG1vYy4gS2FkYSBzZSBvZGx1Y2ltbyB1IGJ1ZHVjbm9zdGkgemEgcHJvcmFjdW4gcmFzdGEga2FvIHBvdGVuY2lqYWxudSB2YXJpamFibHUsIHBvdHJlYm5vIGplIGRhIG9uIHByZSBzdmVnYSBidWRlIHJhY3VuYXQgbmEgbW9ub3RvbmltIHZhcmlqYWJsYW1hLCBrb2plIG5lIG1lbmphanUgem5hayEgIA0KDQpOYXN0YXZsamFtbzogIA0KDQoNCiMjI1RyZXRtYW4gcHJvYmxlbWF0aWNuaWggdmFyaWphYmxpICANCg0KT3Zha28sIGdlbmVyYWxubywgb25vIHN0byBuaXNtbyAobmlzbW8gaHRlbGkga29tZW50YXJpc2F0aSkga29tZW50YXJpc2FsaSBzdSBzaW1ldHJpY25vc3RpIHZhcmlqYWJsaS4gUG96aXRpdm5vIGFzaW1ldHJpY25vIGplIGJhciBwb2xhIHBvc21hdHJhbmloIHZhcmlqYWJsaSB0YWtvIGRhIGJpIHZhbGphbGEgbmVrYSB2cnN0YSBsb2dhcml0bW92YW5lIHRyYW5zZm9ybWFjaWplIHV6IHZvZGplbmplIHJhY3VuYSBvIG5lZ2F0aXZuaW0gdnJlZG5vc3RpbWEgKG5hIHByaW1lciB0cmFuc2Zvcm1hY2lqYSB0aXBhOg0KJFxsb2codmFyICsgXG1pbih2YXIpICsgMSkpJCBiaSBzZSBwb2JyaW51bGEgemEgbmVnYXRpdm5lIHZyZWRub3N0aS4gQm94DQpaYSBuZWdhdGl2bnUgYXNpbWV0cmljbm9zdCBiaSBrb3Jpc3RpbGkgZXZlbnR1YWxubyBla3Nwb25lbmNpamFsbnUgdHJhbnNmb3JtYWNpanUuIFZpZGVjZW1vIHBvc2xlIHBydm9nIHN0ZXB3aXNlYSBpIEFVUk9DLWEuICANCg0KSXBhaywgb3ZkZSBjZW1vIHNlIGtvbmNlbnRyaXNhdGkgbmEgcGFyIHByZXRob2RubyBuYXBvbWVudXRpaCB2YXJpamFibGkuICANCg0KIyMjI1Bva3JpxIdlIG5ldG8ga2FtYXRhICANClBydm8gY2VtbyBwb2RlbGl0aSB2YXJpamFibHUgbmEgbiBpbnRlcnZhbGEuIFphIG9wdGltYWxhbiBicm9qIGludGVydmFsYSBtb3plbW8gaXNrb3Jpc3RpdGkgZHJ1Z3UgZnVua2NpanUga29qYSBpbWEgYWxnb3JpdGFtIGtvamkgYmlyYSBicm9qIGludGVydmFsYSBvZCAxMCBkbyAyMCBuYSBvc25vdnUgb2RyZWRqZW5paCBrcml0ZXJpanVtYSwgdmlkaSBoZWxwIGZ1bmtjaWplIGRvbGUuDQoNCmBgYHtyfQ0KI2tyZWlyYW0gdGFiZWx1IG9kIHBva3JpY2EgbmV0byBrYW1hdGEgaSBpbmRpa2F0b3JhIGRlZmF1bHQtYQ0KZGF0YTwtbHJnZS50cmFpbmluZ1ssYygiZGVmYXVsdC55IiwiUG9rcmljZV9uZXRvX2thbWF0YSIpXQ0KDQpJViA8LSBjcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGEsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KSVZfVmFsdWUgPSBkYXRhLmZyYW1lKElWJFN1bW1hcnkpDQpJVl9WYWx1ZQ0KSVYkVGFibGVzDQpwbG90X2luZm90YWJsZXMoSVYsIlBva3JpY2VfbmV0b19rYW1hdGEiKQ0KYGBgDQpEYWtsZSBvcHRpbXVtIGplIDEwLCBpbWFqdWNpIHUgb2J6aXIgbmVkb3N0YWp1Y2UgdnJlZG5vc3RpIGthbyAxMSBrYXRlZ29yaWp1LiBTYWRhIHJhY3VuYW1vIGZpdGluZyBmdW5rY2lqdSB0cmFuc2Zvcm1hY2lqZS4gR2VuZXJhbG5vLCBtb2dsaSBiaXNtbyBwb2RlbGl0aSB2YXJpamFibHUgdSA4IGthdGVnb3JpY2tpaCwgYWxpIGphIGJpaCBpemJlZ2FvIHRvLiBIYWpkZSBwcnZvIGRhIHZpZGltbyBlbXBpcmlqc2t1IGRpc3RyaWJ1Y2lqdSwgcGEgZGEgZml0dWplbW8uDQpgYGB7cn0NCg0KI2l6cmFjdW5hbSBtZWRpamFudSBwbyBzdmFrb20gYmludQ0KDQoNCiNvdm8gamUgdWplZG5vIGkgcHJ2aSBwdXQgZGEga29yaXN0aW0gbGlzdHUgdSBSLXUNCmNhbGlicmF0ZV9wYXJhbWV0ZXJzPWZ1bmN0aW9uKHRhYmVsYSwgdmFyaWphYmxhLCBkZWZhdWx0LnZhcmlqYWJsYSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicm9qX2Jpbm92YT04LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGxpZXIucXVhbnQ9YygwLjk5LDAuMDEpKXsNCiAgdGFiZWxhJGlkPC0xOm5yb3codGFiZWxhKQ0KICANCiAgI3Byb3ZlcmEgZGEgbGkgamUgY2xhc2EgdGFiZWxlIGRhdGEudGFibGUgb2JqZWthdA0KICBpZighaXMuZGF0YS50YWJsZSh0YWJlbGEpKSB0YWJlbGE9YXMuZGF0YS50YWJsZSh0YWJlbGEpDQogIA0KICAjbW9yYSBvdmFrbyBkYSBiaSBzZSB1IGZ1bmtjaWppIHBvenZhbyBuYXppdiBrYXNuaWplIHUgZXZhbCBmdW5rY2lqaSwgYmFnIHUgZGF0YS50YWJsZSBrb2ppIHNlIG92YWtvIHByZXZhemlsYXppDQogIHZhcmlqYWJsYT1hcy5uYW1lKHZhcmlqYWJsYSkNCiAgZGVmYXVsdC52YXJpamFibGE9YXMubmFtZShkZWZhdWx0LnZhcmlqYWJsYSkNCiAgDQoNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtvbnRpbnVhbG5hIHRyYW5zZm9ybWFjaWphICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyNMb2cgb2RkcyB0cmFuc2Zvcm1hY2lqYSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgICAgICNrcmVpcmFtIGthdGVnb3JpY2t1IHZhcmlqYWJsdS1rb2xvbnUgdSB0YWJlbGkga29qYSBuYW0gZ292b3JpIGtvamVtIHF1YW50aWx1LCBkZWNpbHUuLiAoemF2aXNubyBvZCBicm9qYSBiaW5vdmEpIHByaXBhZGEgZGF0YSBvYnNlcnZhY2lqYSB2YXJpamFibGUNCiAgICAgIHRhYmVsYVssdmFyaWphYmxhX0Jpbjo9cXVhbnRjdXQoDQogICAgICAgIHRhYmVsYVssZXZhbCh2YXJpamFibGEpXSwNCiAgICAgICAgcSA9IHNlcSgwLDEsYnkgPSAxL2Jyb2pfYmlub3ZhKQ0KICAgICAgICApDQogICAgICAgIF0NCiAgICAgIA0KICAgICAgI2tyZWlyYW0gdGFiZWx1IG1lZGlqYW5hIHNhIG9kZ292YXJhanVjaW0gcGRqZXZpbWENCiAgICAgIHRlbXBfZGF0YTwtbmEub21pdCgNCiAgICAgICAgdGFiZWxhWywuKHByb2I9c3VtKGV2YWwoZGVmYXVsdC52YXJpamFibGEpKS8oLk4pLA0KICAgICAgICAgICAgICAgICAgbWVkaWFucyA9IG1lZGlhbihldmFsKHZhcmlqYWJsYSkpKSwNCiAgICAgICAgICAgICAgIGJ5ID0gdmFyaWphYmxhX0Jpbl0NCiAgICAgICAgKVtvcmRlcihtZWRpYW5zKV0NCiAgICAgIA0KICAgIA0KICAgICAgI2ZpdHVqZW0gZnVua2NpanUgbmEgbWVkaWphbmUgcHJlbWEgcGRqZXZpbWENCiAgICAgIGxvZXNfZml0PC1sb2Vzcyhwcm9ifm1lZGlhbnMsZGF0YT10ZW1wX2RhdGEgKQ0KICAgICAgeTwtdGFiZWxhWyxldmFsKHZhcmlqYWJsYSldDQogICAgICANCiAgICAgICNzcmVkanVqZW0gYXV0bGplcmUgcHJlIGZvcmVjYXN0YQ0KICAgICAgdWJvdW5kPC1xdWFudGlsZSh4ID0geSwgcHJvYnMgPSBvdXRsaWVyLnF1YW50WzFdLG5hLnJtID0gVCkNCiAgICAgIGxib3VuZDwtcXVhbnRpbGUoeCA9IHksIHByb2JzID0gb3V0bGllci5xdWFudFsyXSxuYS5ybSA9IFQpDQogICAgICANCiAgICAgICAgI3NyZWRpIHRlIGF1dGxhamVyZSBicmUNCiAgICAgIHlbeT51Ym91bmRdPC11Ym91bmQNCiAgICAgIHlbeTxsYm91bmRdPC1sYm91bmQNCiAgICANCiAgICAgICNmb3JrYXN0dWplbSBrb21wbGV0IHZyZWRub3N0aSB2YXJpamFibGUgc2hvZG5vIGRvYmlqZW5pbSB2cmVkbm9zdGltYSBmaXQgZnVua2NpamUNCiAgICAgIA0KICAgICAgbWVkaWFuLkg8LXRhYmVsYVtldmFsKGRlZmF1bHQudmFyaWphYmxhKT09MCxtZWRpYW4oZXZhbCh2YXJpamFibGEpLG5hLnJtID0gVCldDQogICAgICBtZWRpYW4uRDwtdGFiZWxhW2V2YWwoZGVmYXVsdC52YXJpamFibGEpPT0xLG1lZGlhbihldmFsKHZhcmlqYWJsYSksbmEucm0gPSBUKV0NCiAgICAgIA0KICAgICAgeVtpcy5uYSh5KSAmIHRhYmVsYVssZXZhbChkZWZhdWx0LnZhcmlqYWJsYSldPT0xXTwtbWVkaWFuLkQNCiAgICAgIHlbaXMubmEoeSkgJiB0YWJlbGFbLGV2YWwoZGVmYXVsdC52YXJpamFibGEpXT09MF08LW1lZGlhbi5IDQogICAgICAgIA0KICAgICAgcDwtcHJlZGljdChsb2VzX2ZpdCx5KQ0KICAgIA0KICAgICAgI3BbcDwwXT0wLjAwMDAwMSAjemEgc3Zha2kgc2x1Y2FqDQogICAgICAjIHBbcD4xXT0wLjk5OTk5OQ0KICAgICAgI3RyZWJhanUgbWkgbG9nIG9kZHMgYSBuZSBwZGpldmkNCiAgDQogICAgICB0YWJlbGFbLHRyYW5zZm9ybWlzYW5hX3ZhcmlqYWJsYTo9bG9nKHAvKDEtcCkpXQ0KICAgIA0KICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI0JPWCBDT1ggdHJhbnNmb3JtYWNpamEjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIA0KICAgICAgDQogICAgICAjIHRvIGZpbmQgb3B0aW1hbCBsYW1iZGENCiAgICAgIHZlY3RvcjwtdGFiZWxhWyxldmFsKHZhcmlqYWJsYSldDQogICAgICBsYW1iZGEgPSBCb3hDb3gubGFtYmRhKCB2ZWN0b3IgKQ0KICAgICAgIyBub3cgdG8gdHJhbnNmb3JtIHZlY3Rvcg0KICAgICAgQm94LmNveC52YXJpamFibGEgPSBCb3hDb3goIHZlY3RvciwgbGFtYmRhKQ0KICAgICAgdGFiZWxhWyxCb3guY294LnZhcmlqYWJsYTo9Qm94LmNveC52YXJpamFibGFdDQogICAgICANCiAgDQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5vdmkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogIA0KICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI2xvZyBvZGRzIGJpbm92aSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KICAgIA0KICAgICNyYWN1bmFtIHBkamV2ZSB6YSBzdmFraSBiaW4gaSBkb2RlbGp1amVtIGloIHBvcmVkIHN0YXJlIHZyZWRub3N0aSB2YXJpamFibGUNCiAgICAgICAgI05BIHByZXR2YXJhbSB1IGNoYXJhY3RlciBkYSBiaWggc3JhY3VuYW8gaSB6YSBuamVnYSBERg0KICAgDQogICAgICB0YWJlbGFbLHZhcmlqYWJsYV9CaW5fbnVtZXJpYzo9YXMubnVtZXJpYyh2YXJpamFibGFfQmluKV1bDQogICAgICAgICx2YXJpamFibGFfQmluX251bWVyaWM6PWFzLmNoYXJhY3Rlcih2YXJpamFibGFfQmluX251bWVyaWMpXVsNCiAgICAgICAgICBpcy5uYSh2YXJpamFibGFfQmluX251bWVyaWMpLHZhcmlqYWJsYV9CaW5fbnVtZXJpYzo9Ik5BIl0NCiAgICAgIA0KICAgICAgdGFiZWxhWyxwcm9iOj1zdW0oZXZhbChkZWZhdWx0LnZhcmlqYWJsYSkpLyguTiksYnkgPSB2YXJpamFibGFfQmluX251bWVyaWNdDQogICAgICANCiAgICAgICAgI3JlY29yZCBhIHBsb3QNCiAgICAgIHAxPWdncGxvdChkYXRhPXRhYmVsYSwgYWVzKHZhcmlqYWJsYV9CaW5fbnVtZXJpYykpK2dlb21fYmFyKGFlcyh3ZWlnaHQ9ZXZhbChkZWZhdWx0LnZhcmlqYWJsYSkpKQ0KICAgICAgDQogICAgICAjYWxpIHRyZWJhanUgbWkgbG9nIG9kZHMgbmFyYXZubw0KICAgICAgdGFiZWxhWyxvZGRzOj0ocHJvYi8oMS1wcm9iKSldDQogIA0KICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjd29lIGJpbm92aSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogIA0KICAgICAgZGF0YTwtZGF0YS5mcmFtZSgNCiAgICAgICAgZGVmYXVsdC52YXJpamFibGE9dGFiZWxhWyxldmFsKGRlZmF1bHQudmFyaWphYmxhKV0sDQogICAgICAgIGNvbnRpbnVhbG5hX3ZhcmlqYWJsYT10YWJlbGFbLGV2YWwodmFyaWphYmxhKV0pDQogICAgDQogICAgICBXT0UgPSBjcmVhdGVfaW5mb3RhYmxlcyhkYXRhID0gYXMuZGF0YS5mcmFtZShkYXRhKSwNCiAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnZhcmlqYWJsYSIsIA0KICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGJpbnMgPSBicm9qX2Jpbm92YSkNCiAgICAgIA0KICAgICAgd29lID1XT0UkVGFibGVzJGNvbnRpbnVhbG5hX3ZhcmlqYWJsYVssYygxLDQpXQ0KICAgICANCiAgICAgICNha28gcG9zdG9qZSBtaXNzaW5nIHZhbHVlcyANCiAgICAgIGlmKHdvZVsxLDFdPT0iTkEiKXsNCiAgICAgICB3b2UkInZhcmlqYWJsYV9CaW5fbnVtZXJpYyI9YygiTkEiLDE6YnJval9iaW5vdmEpIA0KICAgICAgfSBlbHNlIHsNCiAgICAgICAgd29lJCJ2YXJpamFibGFfQmluX251bWVyaWMiPWFzLmNoYXJhY3RlcigxOmJyb2pfYmlub3ZhKQ0KICAgICAgfQ0KICAgICAgIA0KICAgICAgd29lLnBsb3Q8LXBsb3RfaW5mb3RhYmxlcyhXT0UsImNvbnRpbnVhbG5hX3ZhcmlqYWJsYSIpDQogICAgDQogICAgICAjcHJlYmFjaSBrYXRlZ29yaWplIHUgYnJvamV2ZSBwYSBuamloIHUgY2hhcmFjdGVyIHpib2cgbmEgaXogcHJldGhvZG5lIHRhYmVsZSwgcGEgbmEgdSBjaGFyYWN0ZXIgam9zIGplZG5vbSBkYSBiaSBtb2dhbyBkYSBnYSB2bG9va2FwdWplDQogICAgICANCiAgICAgIA0KICAgIA0KICAgICAgdGFiZWxhPC1tZXJnZSh4PXRhYmVsYSx5PXdvZSwgYWxsLnggPSBUKVtvcmRlcihpZCldWyxpZDo9TlVMTF0jdmFyaWphYmxhX0Jpbl9udW1lcmljIGplIHRyYXplbmEgdmFydWphYmxhDQogIA0KICANCiAgDQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFVQyB2cmVkbm9zdGkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogICAgICANCiAgICAjcmFjdW5hbSBhdWMgdnJlZG5vc3QsIHN0YXJ1IHBhIG5vdnUgIG5vb29vdnUgDQogICAgI3N0YXJhDQogIGF1cm9jLnM8LWF1YygNCiAgICAgIGFzLm51bWVyaWModGFiZWxhWyxldmFsKGRlZmF1bHQudmFyaWphYmxhKV0pLA0KICAgICAgYXMubnVtZXJpYyh0YWJlbGFbLGV2YWwodmFyaWphYmxhKV0pKQ0KICAgIGF1Yy52cmVkbm9zdC5wcmU8LWFzLm51bWVyaWMoYXVyb2MucykNCiAgICAjbm92YQ0KICBhdXJvYy5uPC1hdWMoDQogICAgICBhcy5udW1lcmljKHRhYmVsYVssZXZhbChkZWZhdWx0LnZhcmlqYWJsYSldKSwNCiAgICAgIGFzLm51bWVyaWModGFiZWxhWyx0cmFuc2Zvcm1pc2FuYV92YXJpamFibGFdKSkNCiAgYXVjLnZyZWRub3N0LnBvc2xlPC1hcy5udW1lcmljKGF1cm9jLm4pDQoNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBPc3RhbGkgR3JhZmljaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgDQogIGNvbC5udW0uZGVmYXVsdDwtZ3JlcCgiZGVmYXVsdCIsIGNvbG5hbWVzKHRhYmVsYSkpDQogIGNvbC5udW0udmFyaWphYmxhPC13aGljaChjb2xuYW1lcyh0YWJlbGEpPT12YXJpamFibGEpDQogIA0KICBvc3RhbGlfcGxvdG92aV9wcmU9cGxvdGluZyh0YWJlbGEsY29sLm51bS52YXJpamFibGEsY29sLm51bS5kZWZhdWx0KQ0KICAgIA0KICBjb2wubnVtLmRlZmF1bHQ8LWdyZXAoImRlZmF1bHQiLCBjb2xuYW1lcyh0YWJlbGEpKQ0KICBjb2wubnVtLnZhcmlqYWJsYTwtd2hpY2goY29sbmFtZXModGFiZWxhKT09InRyYW5zZm9ybWlzYW5hX3ZhcmlqYWJsYSIpDQogIG9zdGFsaV9wbG90b3ZpX3Bvc2xlPXBsb3RpbmcodGFiZWxhLGNvbC5udW0udmFyaWphYmxhLGNvbC5udW0uZGVmYXVsdCkNCiAgDQogIGNvbC5udW0udmFyaWphYmxhPC13aGljaChjb2xuYW1lcyh0YWJlbGEpPT0iQm94LmNveC52YXJpamFibGEiKQ0KICBib3guY294X3Bsb3Rvdmk8LXBsb3RpbmcodGFiZWxhLCBjb2wubnVtLnZhcmlqYWJsYSwgY29sLm51bS5kZWZhdWx0KQ0KICANCiAgb3V0cHV0PC1saXN0KCkNCiAgb3V0cHV0ID0gbGlzdChtb25vdG9uaWNpdHlfZ3JhcGggPSBwMSwNCiAgICAgICAgICAgICAgICBvc3RhbGlfcGxvdG92aV9wcmU9b3N0YWxpX3Bsb3RvdmlfcHJlLA0KICAgICAgICAgICAgICAgIG9zdGFsaV9wbG90b3ZpX3Bvc2xlPW9zdGFsaV9wbG90b3ZpX3Bvc2xlLA0KICAgICAgICAgICAgICAgIHdvZS5wbG90PXdvZS5wbG90LA0KICAgICAgICAgICAgICAgIGF1Yy52cmVkbm9zdD1kYXRhLmZyYW1lKGF1Yy52cmVkbm9zdC5wcmUsYXVjLnZyZWRub3N0LnBvc2xlKSwNCiAgICAgICAgICAgICAgICBmaXRfZnVua2NpamFfb2JqZWthdCA9IGxvZXNfZml0KQ0KDQogIA0KICB0YWJlbGEkdHJhbnNmb3JtaXNhbmFfdmFyaWphYmxhLT5vdXRwdXRbWzddXQ0KICBuYW1lcyhvdXRwdXQpWzddPC1wYXN0ZSh2YXJpamFibGEsIi50ciIsc2VwID0gIiIpDQogIA0KICB0YWJlbGEkb2Rkcy0+b3V0cHV0W1s4XV0NCiAgbmFtZXMob3V0cHV0KVs4XTwtcGFzdGUodmFyaWphYmxhLCIub2RkcyIsc2VwID0gIiIpDQogIA0KICB0YWJlbGEkV09FLT5vdXRwdXRbWzldXQ0KICBuYW1lcyhvdXRwdXQpWzldPC1wYXN0ZSh2YXJpamFibGEsIi5XT0UiLHNlcCA9ICIiKQ0KICANCiAgQm94LmNveC52YXJpamFibGEtPm91dHB1dFtbMTBdXQ0KICBuYW1lcyhvdXRwdXQpWzEwXTwtcGFzdGUodmFyaWphYmxhLCIuQm94LkNveCIsc2VwID0gIiIpDQogIA0KICBib3guY294X3Bsb3RvdmktPm91dHB1dFtbMTFdXQ0KICBuYW1lcyhvdXRwdXQpWzExXTwtcGFzdGUodmFyaWphYmxhLCIuQm94LkNveC5wbG90IixzZXAgPSAiIikNCiAgDQogIG91dHB1dA0KDQp9DQoNClBva3JpY2VfbmV0b19rYW1hdGFyPWNhbGlicmF0ZV9wYXJhbWV0ZXJzKGxyZ2UudHJhaW5pbmcsIGJyb2pfYmlub3ZhPTgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb2tyaWNlX25ldG9fa2FtYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRlZmF1bHQueSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGxpZXIucXVhbnQ9YygwLjk1LDAuMDUpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCg0KUG9rcmljZV9uZXRvX2thbWF0YXIkbW9ub3RvbmljaXR5X2dyYXBoDQpQb2tyaWNlX25ldG9fa2FtYXRhciRvc3RhbGlfcGxvdG92aV9wb3NsZQ0KYGBgDQoNCiMjIyNBc3NldCB0dXJub3Zlcg0KDQpgYGB7cn0NCkFzc2V0X3R1cm5vdmVyPWNhbGlicmF0ZV9wYXJhbWV0ZXJzKGxyZ2UudHJhaW5pbmcsIkFzc2V0X3R1cm5vdmVyIiwiZGVmYXVsdC55IikNCkFzc2V0X3R1cm5vdmVyJG9zdGFsaV9wbG90b3ZpX3Bvc2xlDQpBc3NldF90dXJub3ZlciRtb25vdG9uaWNpdHlfZ3JhcGgNCmBgYA0KDQoNCiMjS2F0ZWdvcmlja2UgcHJvbWVubGppdmU6ICANCg0KUG9zdG9qZSB0cmkga2F0ZWdvcmlja2UgdmFyaWphYmxlIGtvamUgamUgcG90cmVibm8gYW5hbGl6aXJhdGk6ICANCg0KKiAgIFNpZnJhIG9wc3RpbmUtZ2VuZXJhbG5vIHZlbGlraSBicm9qIG9wc3RpbmEgY2UgcHJhdml0aSBwcm9ibGVtLCBwcmVwb3J1a2EgamUgZGEgc2UgcG90ZW5jaWphbG5vIGl6dnJzaSBwb2RlbGEgbmEgQmVvZ3JhZCBpIG9zdGF0YWsgU3JiaWplLCBpbGksIG5hIHZlbGlrZSBncmFkb3ZlIGkgbWFsZSBvcHN0aW5lLCBnZGUgYmkgdSB2ZWxpa2UgZ3JhZG92ZSB1c2xpIEJlb2dyYWQsIE5pcywgTm92aSBTYWQsIGkgbmEga3JhanUgY2VtbyBwb2t1c2F0aSBkYSB1cG90cmViaW1vIGVrb25vbXNrdSByYXp2aWplbm9zdCBvcHN0aW5hIGthbyBwb2themF0ZWxqLiBPbmEgc2UgbWVuamEgc3Zha2UgZ29kaW5lLCBhbGkga29zdHVyIG9zdGFqZSBzbGljYW4sIHBhIGJpc21vIHUgb3ZvbSBkZWx1IHJhenZpamFuamEgbW9kZWxhIHV6ZWxpIHZyZWRub3N0IGl6IDIwMTQuIGdvZGluZSwgYSB1a29saWtvIHNlIGlzcG9zdGF2aSBrYW8gYml0YW4gZmFrdG9yIG1vemVtbyB6YXRyYXppdGkgc2VyaWp1LCBrb2phLCBtZWRqdXRpbSBuZSBpZGUgcHJlIDIwMTAuIGdvZGluZS4NCiogICBTaWZyYSBzZWt0b3JhLWdlbmVyYWxubywgbmUgcG9zdG9qaSBvcHN0ZSBtaXNsamVuamUgbyBvdm9qIHZhcmlqYWJsaSwgbml0aSBvcHJhdmRhbm9zdCB6YXN0byBiaSBvbmEgdXNsYSB1IG9icmFjdW4sIHN0b2ppIGRhIGplIGJyb2ogZGlmb2x0YSBwbyBzZWt0b3JpbWEgcmF6bGljaXQsIGFsaSBuZWtpIHNla3RvcmkgaW1hanUgdnJsbyBtYWxpIGJyb2ogb2JzZXJ2YWNpamEsIHRha28gZGEgY2VtbyBtb3JhdGkgcHJlZ3J1cGlzYXRpIHZhcmlqYWJsZSBuYSBuYWp2ZWNlIHNla3RvcmUgaSBvc3RhbGUsIHphdmlzbm8gb2QgdmVjIG5hdmVkZW5paCBrcml0ZXJpanVtYSB1IHBvY2V0a3Ugb3ZvZyBwb2dsYXZsamEuICANCiogICBTdHJhbmkgaW52ZXN0aXRvci1zaXR1YWNpamEgamUgamFzbmEgIA0KDQpgYGB7cn0NCnJwaXZvdFRhYmxlKGxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UsDQogICAgICAgICAgICByb3dzID0gImRlZmF1bHQueSIsIA0KICAgICAgICAgICAgY29scyA9ICJTdHJhbmlfaW52ZXN0aXRvciIsDQogICAgICAgICAgICBhZ2dyZWdhdG9yTmFtZSA9ICJDb3VudCBhcyBGcmFjdGlvbiBvZiBDb2x1bW5zIikNCmBgYA0KDQoNCg0KIyMjI1NpZnJhIHNla3RvcmE6ICANCg0KDQpgYGB7cn0NCmZyZXFfdGFibGU9ZnVuY3Rpb24oZHRhLGthdGVnb3JpY2FsLGRlZmF1bHQpew0KICBrYXRlZ29yaWNhbD1hcy5uYW1lKGthdGVnb3JpY2FsKQ0KICBkZWZhdWx0PWFzLm5hbWUoZGVmYXVsdCkNCiAgdG1wPWR0YVssLk4sYnk9LihldmFsKGthdGVnb3JpY2FsKSxldmFsKGRlZmF1bHQpKV0NCiAgZnJla3ZlbmNhX3Nla3RvcjwtZGNhc3QodG1wLGV2YWwoa2F0ZWdvcmljYWwpfmV2YWwoZGVmYXVsdCksdmFsdWUudmFyPSJOIikNCiAgZnJla3ZlbmNhX3Nla3RvciRgMGBbaXMubmEoZnJla3ZlbmNhX3Nla3RvciRgMGApXT0wDQogIGZyZWt2ZW5jYV9zZWt0b3IkYDFgW2lzLm5hKGZyZWt2ZW5jYV9zZWt0b3IkYDFgKV09MA0KICB1a3Vwbm88LWZyZWt2ZW5jYV9zZWt0b3IkYDBgK2ZyZWt2ZW5jYV9zZWt0b3IkYDFgDQogIGZyZWt2ZW5jYV9zZWt0b3I8LWNiaW5kLmRhdGEuZnJhbWUoZnJla3ZlbmNhX3Nla3Rvcix1a3Vwbm8pDQogIGZyZWt2ZW5jYV9zZWt0b3JbLGRlZmF1bHRfcmF0ZTo9ZnJla3ZlbmNhX3Nla3RvciRgMWAvdWt1cG5vXQ0KICBhcy5kYXRhLmZyYW1lKGZyZWt2ZW5jYV9zZWt0b3IpDQp9DQoNCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU2lmcmFfc2VrdG9yIiwiZGVmYXVsdC55IikNCmBgYA0KDQpQb3NtYXRyYWp1Y2kgdGFiZWx1IHZpZGltbyBkYSB2ZWMgbmF2ZWRlbmUga3JpdGVyaWp1bWUgemFkb3ZvbGphdmFqdSBDLCBGLCBHIHNla3RvciwgdGFrbyBkYSBvc3RhbGUgbW96ZW1vIHN2cnN0YXRpIHUgcG9zZWJhbiBzZWt0b3IuIE1lZGp1dGltLCBvbm8gc3RvIHV2aWRqYW1vIGplLCBuYXphbG9zdCwgZGEgc3ZhIHRyaSBzZWt0b3JhIGltYWp1IHNsaWNudSBzdG9wdSBkaWZvbHRhIGthbyBpIGtvbXBsZXQgdXpvcmFrLCB6YWtsanVjdWplbW8gZGEgbmFtIGplIG92YSB2YXJpamFibGEgYmVza29yaXNuYS4ub3NpbSBGLCBncmFkamV2aW5hcnN0dm8sIGtvamUgbW96ZW1vIHRyZXRpcmF0aSBrYW8gcG9qZWRpbmFjbnUgdmFyaWphYmx1LiAgDQpgYGB7cn0NCmxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yW2xyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yIT0iRiJdPC0iWiINCmxyZ2UudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3JbbHJnZS50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvciE9IkYiXTwtIloiDQoNCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU2lmcmFfc2VrdG9yIiwiZGVmYXVsdC55IikNCg0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9zaWZyYV9zZWt0b3I8LWxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2VbLGMoImRlZmF1bHQueSIsIlNpZnJhX3Nla3RvciIpXQ0KDQpJVl9zaWZyYV9zZWt0b3I8LWNyZWF0ZV9pbmZvdGFibGVzKGRhdGE9ZGF0YV9zaWZyYV9zZWt0b3IsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KSVZfc2lmcmFfc2VrdG9yJFRhYmxlcw0KDQoNCmBgYA0KKkluZm9ybWF0aW9uIHZhbHVlKiBvZCAwLjA0IGRlbHVqZSBrYW8gcHJpaHZhdGxqaXYsIGFsaSBvdmRlIGltYW1vIHNhbW8gMTkgZGlmb2x0ZXJhIG5hIGplZG51IHZhcmlqYWJsdSBjaWppIGJpbiBuZSB1bGF6aSANCg0KIyMjI1NpZnJhIG9wc3RpbmU6ICANCg0KVSBjaWxqdSBpc2tvcmnFocSHZW5qYSBvdmUgdmFyaWphYmxlIHBvc2VnbnVsaSBzbW8gemEgcG9kZWxvbSBqZWRpbmljYSBMb2thbG5lIHNhbW91cHJhdmUgcG8gZWtvbm9tc2tvaiByYXp2aWplbm9zdGksIGthbyBpIG5hIGRydWd1IHBvZGVsdSBnZGUgc3UgQmVvZ3JhZCwgTm92aSBTQWQgaSBOaXMgdSBqZWRub2oga2F0ZWdvcmlqaSBrYW8gbmFqdmVjaSBncmFkb3ZpLCBhIG9zdGFsaSBncmFkb3ZpIHUgb3N0YWxpbSBrYXRlZ29yaWphbWEsIG5hIGtyYWp1IG1vemVtbyBpIGl6ZHZvaml0aSBzYW1vIEJlb2dyYWQuIFByZWdsZWRham1vIHBydm8ga2Frdm8gamUgc3RhbmplIHBvIG9zdGluYW1hOg0KDQpgYGB7cn0NCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU2lmcmFfb3BzdGluZSIsImRlZmF1bHQueSIpDQpgYGANClV2aWRqYW1vIGRhIEJlb2dyYWQgKG5hanZlcm92YXRuaWplKSBpIE5vdmkgU2FkIGplZGluaSBpbWFqdSBwcmVrbyAxMDAgZHV6bmlrYSwgdGFrbyBkYSBpbWEgc21pc2xhIGRlbGl0aSBuYSBCZW9ncmFkLCBOb3ZpIFNhZCBpIG9zdGFsZSBvcHN0aW5lLiBNZWRqdXRpbSwgdmlkaW1vIGRhIGplIGRlZmF1bHQgcmF0ZSB1IEJlb2dyYWR1IG9rbyAxMCUgc3RvIGplICxvcGV0LCBibGl6dSBkZWZhdWx0IHJhdGVhIHV6b3JrYSwgc2FtaW0gdGltLCBpIEJlb2dyYWQgb3RwYWRhLCBhbGkgYmkgZXZlbnR1YWxubyBtb2dsaSBrb3Jpc3RpdGkgTm92aSBTYWQga2FvIHBvc2VibnUga2F0ZWdvcmlqdS4gUG9rdXNhY2VtbyBkYSB1dmlkaW1vIGRhIGxpIG5hbSBwcmVkbG96ZW5hIHZhcmlqYWJsYSBvIHJhenZpamVub3N0aSBvcHN0aW5hIGRvbm9zaSBuZXN0byBub3ZvIChpenZyc2VuYSBqZSBtYWxhIGtvcmVrY2lqYSBrb2QgWnZlY2Fuai1hIGdkZSBqZSBkb2RhdGEgNCBrYXRlZ29yaWphIGVrb25vbXNrZSByYXp2aWplbm9zdGkgYnVkdWNpIGRhIGplIG9wc3RpbmEgc2EgS29zb3ZhKToNCg0KYGBge3J9DQojdWNpdGF2YW0gcHJpcHJlbWxqZW51IHRhYmVsdSBzYSBrYXRlZ29yaWphbWEgcmF6dmlqZW5vc3RpDQpvcHN0aW5lX3JhenZpamVub3N0IDwtIHJlYWRfZGVsaW0oIkM6L1VzZXJzL21pbG9zLmNpcG92aWMvRGVza3RvcC9Qcm9qZWt0aS9FYXJseSB3YXJuaW5nL1JhenZvam5pIGZvbGRlci9Cb3R0b20gVXAvS29yYWsgNS9vcHN0aW5lX3JhenZpamVub3N0LmNzdiIsIA0KIjsiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKQ0KI29wc3RpbmVfcmF6dmlqZW5vc3QkU2lmcmFfb3BzdGluZTwtZmFjdG9yKG9wc3RpbmVfcmF6dmlqZW5vc3QkU2lmcmFfb3BzdGluZSkNCg0KI2piZyBtb3JhbW8gdm9kaXRpIHJhY3VuYSBvIHJlZG9zbGVkdSBvdmRlISEhISEhDQpscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlJGlkICA8LSAxOm5yb3cobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSkNCmxyZ2UudGVzdC5rYXRlZ29yaWNrZSRpZCAgPC0gMTpucm93KGxyZ2UudGVzdC5rYXRlZ29yaWNrZSkNCg0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZTwtbWVyZ2UobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSxvcHN0aW5lX3JhenZpamVub3N0LGFsbC54ID0gVCkNCmxyZ2UudGVzdC5rYXRlZ29yaWNrZTwtbWVyZ2UobHJnZS50ZXN0LmthdGVnb3JpY2tlLG9wc3RpbmVfcmF6dmlqZW5vc3QsYWxsLnggPSBUKQ0KDQpscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlPC1scmdlLnRyYWluaW5nLmthdGVnb3JpY2tlW29yZGVyKGxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkaWQpLCBdWyxpZDo9TlVMTF0NCmxyZ2UudGVzdC5rYXRlZ29yaWNrZTwtbHJnZS50ZXN0LmthdGVnb3JpY2tlW29yZGVyKGxyZ2UudGVzdC5rYXRlZ29yaWNrZSRpZCksIF1bLGlkOj1OVUxMXQ0KDQpmcmVxX3RhYmxlKGxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UsIlJhenZpamVub3N0IiwiZGVmYXVsdC55IikNCmBgYA0KDQpJbWEgbG9naWtlIHN2cnN0YXRpIGNldHZydHUgaSB0cmVjdSBrb2xvbnUgdSBqZWRudSwgbWFkYSB0aW1lIHBvZGl6ZW1vIGRlZmF1bHQgcmF0ZSBuYSAxNiUgc2EgMTIlLCB0cmViYSBpbWF0aSB1IG9iemlyIGRhIGplIHUgb3Z1IGtvbG9udSB1c2xvIGkgcHJlZHV6ZWNlIGtvamUgamUgc2EgS29zb3ZhIGtvamUgamUgcmFuaWplIGJpbG8gc3Zyc3Rhbm8gdSBvdnUga2F0ZWdvcmlqdSwgYSBrb2plIGplIGRpZm9sdGlyYWxvLiBUaW1lIGJpIGJyb2ogb2JzZXJ2YWNpamEgdSBrbGFzaSAzIGJpbyAkOTlcYXBwcm94MTAwJC4gS29yaXNjZW5qZSBXT0UgaSBJViB1IHNsdWNhanUgdmVsaWtpaCBwcmVkdXplY2EsIGdlbmVyYWxubywgbmlqZSBpenZvZGxqaXZvLCB1c2xlZCBtYWxvZyBicm9qYSBkaWZvbHRlcmEgcG8ga2xhc2kgZmFrdG9yc2tlIHZhcmlqYWJsZSAoW143XSBwcmVkbGF6ZSBiYXIgNTAgZGlmb2x0ZXJhIHBvIGthdGVnb3Jpamkga2xhc2lmaWthY2lqZSksIGlwYWsgcG9nbGVkYWNlbW8gb3ZhIGR2YSBzdGF0aXN0aWthIGthbyBwdXRva2F6IGkgaW1hdGkgdSB2aWR1IHByZWRsb2cgW144XSBnZGUgbmF2b2RpIHphIElWIHN0YXRpc3RpayBzbGVkZWNlOg0KDQoqICAgVWtvbGlrbyBqZSBtYW5qaSBvZCAwLjAyLCBuaWplIG5hbSBvZCBwcmVrZSB2YXpub3N0aQ0KKiAgIFVrb2xpa28gamUgaXptZWRqdSAwLjAyIGkgMC4xIG9uZGEgcG9zdG9qaSBzbGFiYSBkaXNrcmltaW5hY2lqYSBpIHZlemEgc2EgcmFjaWpvbSBzYW5zaQ0KKiAgIFVrb2xpa28gamUgaXptZWRqdSAwLjEgaSAwLjMgb25kYSBwb3N0b2ppIHNyZWRuamUgamFrYSB2ZXlhIHNhIHJhY2lqb20gc2Fuc2kgaSANCiogICBQcmVrbyAwLjMgb3luYWNhdmEgc2pham51IHBvdmV5YW5vc3Qgc2EgZGlza3JpbWluYWNpam9tIGkgcmFjaWpvbSBzYW5zaSAoU3Jwc2tpIHphICpHb29kL0JhZCBvZGRzIHJhdGlvKikgIA0KDQpTcG9qaWxpIHNtbyA0IGkgMyBrYXRlZ29yaWp1DQoNCmBgYHtyfQ0KI2tyZWlyYW0gbm92dSB2YXJpamFibHUgZ2RlIDQgcHJpcGFqYW0gM2pjaQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdFtscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlJFJhenZpamVub3N0PT00XTwtMw0KbHJnZS50ZXN0LmthdGVnb3JpY2tlJFJhenZpamVub3N0W2xyZ2UudGVzdC5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdD09NF08LTMNCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiUmF6dmlqZW5vc3QiLCJkZWZhdWx0LnkiKQ0KYGBgDQpgYGB7cn0NCg0KZGF0YV9vcHN0aW5lX3BvX3JhenZpamVub3N0aTwtbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZVssYygiZGVmYXVsdC55IiwiUmF6dmlqZW5vc3QiKV0NCklWX29wc3RpbmVfcG9fcmF6dmlqZW5vc3RpPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfb3BzdGluZV9wb19yYXp2aWplbm9zdGksDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl9vcHN0aW5lX3BvX3JhenZpamVub3N0aSRUYWJsZXMNCg0KYGBgDQpEb2JpbGkgc21vIElWIG9rbyAwLjA3IHN0byB6YWRvdm9samF2YSBtZWRqdXRpbSBqYWtvIGplIG1hbGkgYnJvaiBkaWZvbHRhIHUga2F0ZWdvcmlqaSAzIGltYWp1Y2kgdSB2aWR1IGJyb2ogb3BzdGluYSBrb2plIHNwYWRhanUgdSBuanUsIHNwYWphbW8gMiBpIDMNCmBgYHtyfQ0KI2tyZWlyYW0gbm92dSB2YXJpamFibHUgZ2RlIDMgaSAyIHNwYWphbQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdFtscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlJFJhenZpamVub3N0PT0zXTwtMg0KbHJnZS50ZXN0LmthdGVnb3JpY2tlJFJhenZpamVub3N0W2xyZ2UudGVzdC5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdD09M108LTINCg0KZnJlcV90YWJsZShscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlLCJSYXp2aWplbm9zdCIsImRlZmF1bHQueSIpDQpgYGANCmBgYHtyfQ0KZGF0YV9vcHN0aW5lX3BvX3JhenZpamVub3N0aTwtbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZVssYygiZGVmYXVsdC55IiwiUmF6dmlqZW5vc3QiKV0NCklWX29wc3RpbmVfcG9fcmF6dmlqZW5vc3RpPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfb3BzdGluZV9wb19yYXp2aWplbm9zdGksDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl9vcHN0aW5lX3BvX3JhenZpamVub3N0aSRTdW1tYXJ5DQpgYGANCk9rbyAwLjA0IHN0byBiaSBtb2dsbyBkYSBuYW0gem5hY2kgbmVzdG8NCg0KUG9rdXNham1vIHNhZGEgc2EgTm92aW0gU2Fkb206DQoNCmBgYHtyfQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lW2xyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZSE9Ijg5MDEwIl08LSIwMDAwIg0KbHJnZS50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmVbbHJnZS50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUhPSI4OTAxMCJdPC0iMDAwMCINCg0KZnJlcV90YWJsZShscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlLCJTaWZyYV9vcHN0aW5lIiwiZGVmYXVsdC55IikNCmBgYA0KDQpgYGB7cn0NCmRhdGFfMm9wc3RpbmU8LWxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2VbLGMoImRlZmF1bHQueSIsIlNpZnJhX29wc3RpbmUiKV0NCklWXzJvcHN0aW5lPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfMm9wc3RpbmUsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl8yb3BzdGluZSRTdW1tYXJ5DQpgYGANCklwYWsgY2VtbyBpY2kgc2Egb3BzdGluYW1hIHBvIHJhenZpamVub3N0aQ0KDQojIyMjU3RyYW5pIGludmVzdGl0b3IgIA0KDQpQb2dsZWRham1vIHBydm8gZnJla3ZlbmNpb251IHRhYmVsdQ0KDQpgYGB7cn0NCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU3RyYW5pX2ludmVzdGl0b3IiLCJkZWZhdWx0LnkiKQ0KYGBgDQpQb3N0b2ppIG9jaWdsZWRuYSByYXpsaWthLCBpbWFqdWNpIHUgdmlkdSBkYSBvdmRlIGltYW1vIHNhbW8gZHZlIHZhcmlqYWJsZSwgdG8gamUgaSBvY2VraXZhbm8sIGhhamRlIGRhIHZpZGltbyBJVjoNCmBgYHtyfQ0KZGF0YV9zdHJhbmlfaW52ZXN0aXRvcjwtbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZVssYygiZGVmYXVsdC55IiwiU3RyYW5pX2ludmVzdGl0b3IiKV0NCklWX3N0cmFuaV9pbnZlc3RpdG9yPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfc3RyYW5pX2ludmVzdGl0b3IsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl9zdHJhbmlfaW52ZXN0aXRvciRUYWJsZXMNCmBgYA0KSW1hbW8gSVYgb2tvIDAuMDMuIFV6ZWNlbW8gb3Zha28uDQoNCg0KDQojIyNFdmFsdWFjaWphIHJlZ3Jlc2lqZQ0KDQpEb3NhZGFzbmppIHJlenVsdGF0aToNCg0KT3RwYWRhbmplIHVzbGVkIGBOQWAgdnJlZG5vc3RpLCBwcmV6aXZlbGUgc3Ugc2xlZGVjZSB2YXJpamFibGU6DQpgYGB7cn0NCnN1bW1hcnlfdGFibGU8LWFzLmRhdGEuZnJhbWUoc3VtbWFyeV90YWJsZSkNCnByZXppdmVsaS5OQTwtcm93bmFtZXMoc3VtbWFyeV90YWJsZVtzdW1tYXJ5X3RhYmxlJE5Bc3BlcmNlbnQ8MTAsXSkNCmtuaXRyOjprYWJsZShwcmV6aXZlbGkuTkEpDQpgYGANCg0KQ2lzY2VuamUgdXNsZWQga29yZWxhY2lqYSBpIEFVUk9DLWEgbWFuamVnIG9kIDAuNTUNCmBgYHtyfQ0KcHJleml2ZWxpLmNvcnIuQVVDPC1yb3cubmFtZXMoY2xlYW5fY29yKQ0KYGBgDQoNClByZXNlayBvdmEgZHZhIG5hc3RhdmxqYSB1IG11bHRpdmFyaWF0ZS4NCg0KYGBge3J9DQojb2RhYnJhbmk8LWMoIlJhY2lvX25vdmNhbmVfbGlrdmlkbm9zdGlfKENhc2hfcmF0aW8pIixpbnRlcnNlY3QocHJleml2ZWxpLk5BLHByZXppdmVsaS5jb3JyLkFVQykpDQpvZGFicmFuaTwtaW50ZXJzZWN0KHByZXppdmVsaS5OQSxwcmV6aXZlbGkuY29yci5BVUMpDQpgYGANCg0KDQoNCk92ZGUgcG9kc2VjYW1vIGRhIGNlbW8gaXBhayBkb2RhdGkga2FzaCByYWNpbyB1IGdydXB1LiBOaXNtbyBwcm92ZXJhdmFsaSBvdmRlIHJlZG92ZSBhbGkgYmkgdHJlYmFsbyBrYWRhIGJ1ZGVtbyByYWRpbGEgc2EgbWFsaW0gaSBzcmVkbmppbSBwcmVkdXplY2ltYS4gU3JlZGltbyBzYWRhIGBOQWAgdnJlZG5vc3RpOg0KDQpGdW5rY2lqYSB6YSBuZWRvc3RhanVjZSBpIGVrc3RyZW1lOg0KDQpgYGB7cn0NCnJlcGxhY2Vfb3V0bGllcl93aXRoX3F1YW50aWxlIDwtDQogIGZ1bmN0aW9uKHgsDQogIHF1YW50ID0gVFJVRSwNCiAgcHJvYnMgPSBjKDAuMDEsIDAuOTkpLA0KICBuYS5ybSA9IFRSVUUpIHsNCiAgaWYgKHF1YW50ID09IFQpIHsNCiAgcW50IDwtIHF1YW50aWxlKHgsIHByb2JzID0gcHJvYnMsIG5hLnJtID0gbmEucm0pICAjIGdldCAlaWxlcw0KICBVIDwtIHFudFsyXQ0KICBMIDwtIHFudFsxXQ0KICB5IDwtIHgNCiAgeVt4IDwgTF0gPC0gTCAgIyByZXBsYWNlIHZhbHVlcyBiZWxvdyBsb3dlciBib3VuZHMNCiAgeVt4ID4gVV0gPC0gVQ0KICB5DQogIH0gZWxzZSBpZiAocXVhbnQgPT0gRikgew0KICBxbnQgPC0gcXVhbnRpbGUoeCwgcHJvYnMgPSBjKC4yNSwgLjc1KSwgbmEucm0gPSBuYS5ybSkgICMgZ2V0ICVpbGVzDQogIEggPC0gMyAqIElRUih4LCBuYS5ybSA9IG5hLnJtKSAgIyBvdXRsaWVyIGxpbWl0IHRocmVzaG9sZA0KICB5IDwtIHgNCiAgeVt4IDwgKHFudFsxXSAtIEgpXSA8LQ0KICAocW50WzFdIC0gSCkgICMgcmVwbGFjZSB2YWx1ZXMgYmVsb3cgbG93ZXIgYm91bmRzDQogIHlbeCA+IChxbnRbMl0gKyBIKV0gPC0NCiAgKHFudFsyXSArIEgpICAjIHJlcGxhY2UgdmFsdWVzIGFib3ZlIGhpZ2hlciBib3VuZA0KICB5ICAjIHJldHVybnMgdHJlYXRlZCB2YXJpYWJsZQ0KICB9IA0KICANCiAgfQ0KICANCiAgDQogIHJlcGxhY2VfbWlzc2luZ193aXRoX21lZGlhbiA8LQ0KICBmdW5jdGlvbih4LA0KICBkZWZhdWx0LmNvbG9uYSA9IGFzLm5hbWUoZGVmYXVsdC55KSwNCiAgcHJvYnMgPSBjKDAuMDEsIDAuOTkpLA0KICBuYS5ybSA9IFRSVUUsDQogIHRyYWluaW5nID0gVCwNCiAgLi4uKSB7DQogIHggPCBhcy5kYXRhLmZyYW1lKHgpDQogIG1lZGlhbi4gPC0NCiAgbWVkaWFuKHgsIG5hLnJtID0gbmEucm0pDQogIG1lZGlhbi5oID0gbWVkaWFuKHhbZGVmYXVsdC5jb2xvbmEgPT0gMF0sIG5hLnJtID0gbmEucm0pDQogIG1lZGlhbi5kID0gbWVkaWFuKHhbZGVmYXVsdC5jb2xvbmEgPT0gMV0sIG5hLnJtID0gbmEucm0pDQogIA0KICBpZiAodHJhaW5pbmcgPT0gVCkgew0KICB4W2lzLm5hKHgpICYgZGVmYXVsdC5jb2xvbmEgPT0gMF0gPC0gbWVkaWFuLmgNCiAgeFtpcy5uYSh4KSAmDQogIGRlZmF1bHQuY29sb25hID09IDFdIDwtDQogIG1lZGlhbi5kDQogIH0gZWxzZSB7DQogIHhbaXMubmEoeCldIDwtIG1lZGlhbi4NCiAgfQ0KICB4DQogIH0NCiAgDQogIA0KICANCiAgDQogIHJlcGxhY2Vfb3V0bGllcl93aXRoX25hIDwtIGZ1bmN0aW9uKHgscXVhbnQgPSBUUlVFLA0KICBwcm9icyA9IGMoMC4wMSwgMC45OSksDQogIG5hLnJtID0gVFJVRSkgew0KICBpZiAocXVhbnQgPT0gVCkgew0KICBxbnQgPC0gcXVhbnRpbGUoeCwgcHJvYnMgPSBwcm9icywgbmEucm0gPSBuYS5ybSkgICMgZ2V0ICVpbGVzDQogIFUgPC0gcW50WzJdDQogIEwgPC0gcW50WzFdDQogIHkgPC0geA0KICB5W3ggPCBMXSA8LSBOQSAgIyByZXBsYWNlIHZhbHVlcyBiZWxvdyBsb3dlciBib3VuZHMNCiAgeVt4ID4gVV0gPC0gTkENCiAgeQ0KICB9IGVsc2UgaWYgKHF1YW50ID09IEYpIHsNCiAgcW50IDwtIHF1YW50aWxlKHgsIHByb2JzID0gYyguMjUsIC43NSksIG5hLnJtID0gbmEucm0pICAjIGdldCAlaWxlcw0KICBIIDwtIDMgKiBJUVIoeCwgbmEucm0gPSBuYS5ybSkgICMgb3V0bGllciBsaW1pdCB0aHJlc2hvbGQNCiAgeSA8LSBOQQ0KICB5W3ggPCAocW50WzFdIC0gSCldIDwtIE5BICAjIHJlcGxhY2UgdmFsdWVzIGJlbG93IGxvd2VyIGJvdW5kcw0KICB5W3ggPiAocW50WzJdICsgSCldIDwtIE5BICAjIHJlcGxhY2UgdmFsdWVzIGFib3ZlIGhpZ2hlciBib3VuZA0KICB5ICAjIHJldHVybnMgdHJlYXRlZCB2YXJpYWJsZQ0KICANCiAgfQ0KICB9DQogIA0KIA0KICANCiAgDQogIHJlcGxhY2VfbWlzc2luZ193aXRoX2tubiA8LSBmdW5jdGlvbih4LCByZXNwb25zZV9uYW1lID0gImRlZmF1bHQueSIsIHRyYWluaW5nID0gVCkgew0KICAgIA0KICAgIHggPC0gYXMuZGF0YS5mcmFtZSh4KQ0KDQogICAgcmVzcG9uc2U8LXhbLGV2YWwocmVzcG9uc2VfbmFtZSldDQogICAgaWYgKHRyYWluaW5nID09IEYpIHsNCiAgICAgIGlmIChhbnlOQSh4KSkgew0KICAgICAgICB4WywhbmFtZXMoeCkgJWluJSByZXNwb25zZV9uYW1lXSA8LQ0KICAgICAgICAgIGtubkltcHV0YXRpb24oeFssIW5hbWVzKHgpICVpbiUgcmVzcG9uc2VfbmFtZV0pICAjIG1pc3NpbmcgdmFsdWUgdHJlYXRtZW50DQogICAgICAgIH0NCiAgICB9IGVsc2Ugew0KICAgICAgaWYoYW55TkEoeCkpIHsNCiAgICAgICAgeFtyZXNwb25zZT09MSwhbmFtZXMoeCkgJWluJSByZXNwb25zZV9uYW1lXSA8LQ0KICAgICAgICAgIGtubkltcHV0YXRpb24oeFtyZXNwb25zZT09MSwhbmFtZXMoeCkgJWluJSByZXNwb25zZV9uYW1lXSkgICMgbWlzc2luZyB0cmVhdG1lbnQNCiAgICAgICAgfQ0KICAgICAgICANCiAgICAgIGlmIChhbnlOQSh4KSkgew0KICAgICAgICB4W3Jlc3BvbnNlPT0wLCFuYW1lcyh4KSAlaW4lIHJlc3BvbnNlX25hbWVdIDwtDQogICAgICAgICAga25uSW1wdXRhdGlvbih4W3Jlc3BvbnNlPT0wLCFuYW1lcyh4KSAlaW4lIHJlc3BvbnNlX25hbWVdKSAgIyBtaXNzaW5nIHZhbHVlIHRyZWF0bWVudCAgDQogICAgICAgIA0KICAgICAgICB9DQogICAgICANCiAgICB9DQogICAgYXMuZGF0YS50YWJsZSh4KQ0KICAgIH0NCiAgICANCiNpbnB1dERhdGFfY29udCA8LSBhcy5kYXRhLmZyYW1lIChzYXBwbHkoY2xlYW5fYlssOTozNF0sIHJlcGxhY2Vfb3V0bGllcl93aXRoX21pc3NpbmcpKSAgIyB0aGlzIHdpbGwgbWFrZSBvdXRsaWVycyBhcyBOQSANCiNzdW1tYXJ5X3RhYmxlMjwtc2FwcGx5KGlucHV0RGF0YV9jb250LG15LnN1bW1hcnksYXJnPVQpDQpgYGANCg0KS3JlaXJhbW8gemF2cnNuaSB1em9yYWs6ICANCl9fX19fX19fX19fX19fX19fX19fX18gIA0KDQpUcmV0bWFuIG5lZG9zdGFqdWNpaCBpIHRyZXRtYW4gYXV0bGFqZXJhLCBwb3RvbSBkb2RhamVtbyBrYXRlZ29yaWNrZQ0KDQpgYGB7cn0NCmZpbmFsbmlfbHJnZTwtbHJnZS50cmFpbmluZ1ssYyhvZGFicmFuaSksIHdpdGg9Rl0NCg0KI2ZpbmFsbmlfbHJnZTwtY2JpbmQuZGF0YS5mcmFtZShmaW5hbG5pX2xyZ2UsQXNzZXRfdHVybm92ZXIkQXNzZXRfdHVybm92ZXIudHIsUG9rcmljZV9uZXRvX2thbWF0YSRQb2tyaWNlX25ldG9fa2FtYXRhLnRyKQ0KDQojZmluYWxuaV9scmdlPC1hcy5kYXRhLnRhYmxlKHNhcHBseShmaW5hbG5pX2xyZ2UscmVwbGFjZV9vdXRsaWVyX3dpdGhfcXVhbnRpbGUpKQ0KZmluYWxuaV9scmdlPC1hcy5kYXRhLnRhYmxlKHNhcHBseShmaW5hbG5pX2xyZ2UscmVwbGFjZV9vdXRsaWVyX3dpdGhfbmEpKQ0KZmluYWxuaV9scmdlJGRlZmF1bHQueTwtbHJnZS50cmFpbmluZyRkZWZhdWx0LnkNCg0KZmluYWxuaV9scmdlPC1yZXBsYWNlX21pc3Npbmdfd2l0aF9rbm4oZmluYWxuaV9scmdlKQ0KDQpmaW5hbG5pX2xyZ2UkZGVmYXVsdC55PC1OVUxMDQpgYGANCg0KDQpgYGB7cn0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3BjaW9ubyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCkFBPC1kYXRhLmZyYW1lKDE6MTI1NSk7bj0xICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCmZpbmFsbmlfbHJnZSRkZWZhdWx0LnkgPC0gZGVmYXVsdC55ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCmZvcihpIGluIG5hbWVzKGZpbmFsbmlfbHJnZSlbImRlZmF1bHQueSIgIT0gbmFtZXMoZmluYWxuaV9scmdlKV0pIHsNCiAgDQogIG4gPSBuICsgMQ0KICB0bXAgPC0gY2FsaWJyYXRlX3BhcmFtZXRlcnMoZmluYWxuaV9scmdlLCBpLCAiZGVmYXVsdC55IikNCiAgQUEgPC0gY2JpbmQuZGF0YS5mcmFtZShBQSwgdG1wW1s3XV0pDQogIG5hbWVzKEFBKVtuXSA8LSBuYW1lcyhmaW5hbG5pX2xyZ2UpW25dDQp9DQoNCg0KZmluYWxuaV9scmdlIDwtIEFBDQpyZW1vdmUoQUEpDQpmaW5hbG5pX2xyZ2VbLCAxXSA8LSBOVUxMDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KZmluYWxuaV9scmdlJGRlZmF1bHQueSA8LSBkZWZhdWx0LnkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQpmaW5hbG5pX2xyZ2UgPC0gYXMuZGF0YS50YWJsZShmaW5hbG5pX2xyZ2UpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KYGBgDQoNCg0KYGBge3J9DQojc3BhamFtbyBzYSBrYXRlZ29yaWNraW0gaSBza2lkYW1vIHBhciB2aXNrb3ZhIGthdGVnb3JpY2tpaCwgdmVsaWNpbmEsIHRvdGFsDQoNCmZpbmFsbmlfbHJnZSA8LQ0KICBjYmluZC5kYXRhLmZyYW1lKGZpbmFsbmlfbHJnZSwgbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSlbLCBjKCJWZWxpY2luYSIsICJUb3RhbCIsICJTaWZyYV9zZWt0b3IiLCJTaWZyYV9vcHN0aW5lIikgOj0NCiAgTlVMTF0NCiAgDQoNCiNwcmV0dmFyYW0ga2F0ZWdvcmlja2UgdSBmYWt0b3IgZGEgYmkgaWggZ2xtIHBvc21hdHJhbyBrYW8ga2F0ZWdvcmlja2UNCmZpbmFsbmlfbHJnZSRSYXp2aWplbm9zdCA8LSBhcy5mYWN0b3IoZmluYWxuaV9scmdlJFJhenZpamVub3N0KQ0KZmluYWxuaV9scmdlJFN0cmFuaV9pbnZlc3RpdG9yIDwtDQphcy5mYWN0b3IoZmluYWxuaV9scmdlJFN0cmFuaV9pbnZlc3RpdG9yKQ0KYGBgDQoNCkR1Z28gb2Nla2l2YW5pIHRyZW51dGFrOg0KDQpgYGB7cn0NCg0KbW9kZWwubnVsbCA9IGdsbShkZWZhdWx0LnkgfiAxLA0KICAgICAgICAgICAgICAgICBkYXRhPWZpbmFsbmlfbHJnZSwNCiAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKQ0KICAgICAgICAgICAgICAgICApDQoNCm1vZGVsLmZ1bGwgPSBnbG0oZGVmYXVsdC55IH4gLiwNCiAgICAgICAgICAgICAgICAgZGF0YT1maW5hbG5pX2xyZ2UsDQogICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IikNCiAgICAgICAgICAgICAgICAgKQ0KICAgIA0Kc3RlcChtb2RlbC5udWxsLA0KICAgICBzY29wZSA9IGxpc3QodXBwZXI9bW9kZWwuZnVsbCxsb3dlcj1tb2RlbC5udWxsKSwNCiAgICAgICAgICAgICBkaXJlY3Rpb249ImZvcndhcmQiLA0KICAgICAgICAgICAgIA0KICAgICAgICAgICAgIGRhdGE9ZmluYWxuaV9scmdlLHRyYWNlPTApDQpgYGANCg0KYGBge3J9DQptb2RlbDEgPC0gZ2xtKGZvcm11bGEgPWRlZmF1bHQueX5gUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbylgK1N0ZXBlbl96YWR1emVub3N0aStHb3Rvdmluc2tpX2Npa2x1c18xK1ZyZW1lX25hcGxhdGVfcG90cmF6aXZhbmphK1N0b3BhX3ByaW5vc2FfbmFfc29wc3R2ZW5pX2thcGl0YWxfcHJlX29wb3Jleml2YW5qYStDZW5hX3R1ZGppaF9penZvcmFfc3JlZHN0YXZhLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIA0KICAgIGRhdGEgPSBmaW5hbG5pX2xyZ2UpDQoNCg0KbW9kZWwxLmRhdGEuZnJhbWU8LWRhdGEuZnJhbWUoZml0MT1tb2RlbDEkZml0dGVkLnZhbHVlcywgZGlmMT1tb2RlbDEkbW9kZWwkZGVmYXVsdC55KQ0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQpzdGVwKG1vZGVsLmZ1bGwsDQogICAgIHNjb3BlID0gbGlzdChsb3dlcj1tb2RlbC5mdWxsLHVwcGVyPW1vZGVsLm51bGwpLA0KICAgICAgICAgICAgIGRpcmVjdGlvbj0iYmFja3dhcmQiLA0KICAgICAgICAgICAgIGRhdGE9ZmluYWxuaV9scmdlLCB0cmFjZT0wKQ0KYGBgDQpgYGB7cn0NCiBtb2RlbDI8LSAgZ2xtKGZvcm11bGEgPSBkZWZhdWx0LnkgfiBgUmlnb3Jvem5pX3JhY2lvX3JlZHVrb3ZhbmVfKG1vbmV0YXJuZSlfbGlrdmlkbm9zdGlgICsgDQogICAgYFJhY2lvX25vdmNhbmVfbGlrdmlkbm9zdGlfKENhc2hfcmF0aW8pYCArIFN0ZXBlbl96YWR1emVub3N0aSArIA0KICAgIGBSYWNpb19wb2tyaWNhX2thbWF0YV96YXJhZG9tX3ByZV9rYW1hdGFfaV9wb3JlemFfKEludGVyZXN0X0NvdmVyYWdlX1JhdGlvKWAgKyANCiAgICBSYWNpb19wb2tyaWNhX29icnRuZV9pbW92aW5lICsgR290b3ZpbnNraV9jaWtsdXNfMSArIFZyZW1lX2tyZWRpdGlyYW5qYV9rdXBhY2EgKyANCiAgICBWcmVtZV9uYXBsYXRlX3BvdHJheml2YW5qYSArIFZyZW1lX3BsYWNhbmphX2RvYmF2bGphY2ltYSArIA0KICAgIFN0b3BhX3ByaW5vc2FfbmFfc29wc3R2ZW5pX2thcGl0YWxfcHJlX29wb3Jleml2YW5qYSArIFN0b3BhX3ByaW5vc2FfbmFfdWt1cG5hX3NyZWRzdHZhX3ByZV9vcG9yZXppdmFuamEgKyANCiAgICBDZW5hX3R1ZGppaF9penZvcmFfc3JlZHN0YXZhICsgVDE0ICsgVDIxICsgdWRlb191X2thcGl0YWx1ICsgDQogICAgU3RyYW5pX2ludmVzdGl0b3IgKyBSYXp2aWplbm9zdCwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCANCiAgICBkYXRhID0gZmluYWxuaV9scmdlKQ0KDQptb2RlbDIuZGF0YS5mcmFtZT1kYXRhLmZyYW1lKGZpdDI9bW9kZWwyJGZpdHRlZC52YWx1ZXMsIGRpZjI9bW9kZWwyJG1vZGVsJGRlZmF1bHQueSkNCg0KYGBgDQoNCldhbGQgc3RhdGlzdGlrOg0KDQpgYGB7cn0NCmxpYnJhcnkoY2FyKQ0KDQpBbm92YShtb2RlbDEsIHR5cGU9IklJIiwgdGVzdD0iV2FsZCIpDQpgYGANCkxhbmdyYW5nZSBtdWx0aXBsaWVyIHRlc3Q6DQoNCmBgYHtyfQ0KYW5vdmEobW9kZWwyLA0KICAgICAgbW9kZWwubnVsbCwNCiAgICAgIHRlc3Q9IkNoaXNxIikNCmBgYA0KDQoNCg0KRHJ1Z2kgbmFjaW4NCg0KYGBge3J9DQogIGF1cm9jLjE8LWF1YygNCiAgICAgIGFzLm51bWVyaWMobW9kZWwxLmRhdGEuZnJhbWUkZGlmMSksDQogICAgICBhcy5udW1lcmljKG1vZGVsMS5kYXRhLmZyYW1lJGZpdDEpKQ0KIGF1cm9jLjI8LWF1YygNCiAgICAgIGFzLm51bWVyaWMobW9kZWwyLmRhdGEuZnJhbWUkZGlmMiksDQogICAgICBhcy5udW1lcmljKG1vZGVsMi5kYXRhLmZyYW1lJGZpdDIpKQ0KYyhhdXJvYy4xLGF1cm9jLjIpDQoNCmBgYA0KDQojIyN2YWxpZGFjaW9uaSB1em9yYWsgIA0KMTA2MjY0IDk2OTQ2DQpgYGB7cn0NCmZpbmFsbmlfbHJnZS50ZXN0PC1scmdlLnRlc3RbLGMob2RhYnJhbmkpLCB3aXRoPUZdDQoNCiNmaW5hbG5pX2xyZ2U8LWNiaW5kLmRhdGEuZnJhbWUoZmluYWxuaV9scmdlLEFzc2V0X3R1cm5vdmVyJEFzc2V0X3R1cm5vdmVyLnRyLFBva3JpY2VfbmV0b19rYW1hdGEkUG9rcmljZV9uZXRvX2thbWF0YS50cikNCg0KZmluYWxuaV9scmdlLnRlc3Q8LWFzLmRhdGEudGFibGUoc2FwcGx5KGZpbmFsbmlfbHJnZS50ZXN0LHJlcGxhY2Vfb3V0bGllcl93aXRoX25hKSkNCg0KZmluYWxuaV9scmdlLnRlc3QkZGVmYXVsdC55PC1scmdlLnRlc3QkZGVmYXVsdC55DQoNCmZpbmFsbmlfbHJnZS50ZXN0PC1yZXBsYWNlX21pc3Npbmdfd2l0aF9rbm4oZmluYWxuaV9scmdlLnRlc3QsdHJhaW5pbmcgPSBGKQ0KZmluYWxuaV9scmdlLnRlc3QkZGVmYXVsdC55PC1OVUxMDQoNCg0KZmluYWxuaV9scmdlLnRlc3QgPC0NCiAgY2JpbmQuZGF0YS5mcmFtZShmaW5hbG5pX2xyZ2UudGVzdCwgbHJnZS50ZXN0LmthdGVnb3JpY2tlKVssIGMoIlZlbGljaW5hIiwgIlRvdGFsIiwgIlNpZnJhX3Nla3RvciIsIlNpZnJhX29wc3RpbmUiKSA6PQ0KICBOVUxMXQ0KICANCg0KI3ByZXR2YXJhbSBrYXRlZ29yaWNrZSB1IGZha3RvciBkYSBiaSBpaCBnbG0gcG9zbWF0cmFvIGthbyBrYXRlZ29yaWNrZQ0KZmluYWxuaV9scmdlLnRlc3QkUmF6dmlqZW5vc3QgPC0gYXMuZmFjdG9yKGZpbmFsbmlfbHJnZS50ZXN0JFJhenZpamVub3N0KQ0KZmluYWxuaV9scmdlLnRlc3QkU3RyYW5pX2ludmVzdGl0b3IgPC0NCmFzLmZhY3RvcihmaW5hbG5pX2xyZ2UudGVzdCRTdHJhbmlfaW52ZXN0aXRvcikNCg0KDQptb2RlbDEucHJlZDwtYXMubnVtZXJpYyhwcmVkaWN0KG1vZGVsMSwgbmV3ZGF0YSA9IGZpbmFsbmlfbHJnZS50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQptb2RlbDIucHJlZDwtYXMubnVtZXJpYyhwcmVkaWN0KG1vZGVsMiwgbmV3ZGF0YSA9IGZpbmFsbmlfbHJnZS50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQpkaWY8LWFzLm51bWVyaWMoZmluYWxuaV9scmdlLnRlc3QkZGVmYXVsdC55KQ0KDQphdXJvYy4xLnByZWQ8LWF1YyggZGlmLG1vZGVsMS5wcmVkKQ0KYXVyb2MuMi5wcmVkPC1hdWMoIGRpZixtb2RlbDIucHJlZCkNCmMoYXVyb2MuMS5wcmVkLGF1cm9jLjIucHJlZCkNCg0KYGBgDQoNCg0KDQpbXjNdOiBWaWRpIFJhdGluZyBNb2RlbHMgYW5kIFZhbGlkYXRpb24gLSAgT2VzdGVycmVpY2hpc2NoZSBOYXRpb25hbGJhbmsgKE9lTkIpLiAgDQpbXjRdOiBIYXlkZW4sIEUuLCAmIFBvcmF0aCwgRC4gKDIwMTEpLiBTdGF0aXN0aWNhbCBNZXRob2RzIHRvIERldmVsb3AgUmF0aW5nIE1vZGVscy4gSW4gQi4gRW5nZWxtYW5uLCBhbmQgUi4gUmF1aG1laWVyIChFZHMuKSwgVGhlIEJhc2VsIElJIFJpc2sgUGFyYW1ldGVyczogRXN0aW1hdGlvbiwgVmFsaWRhdGlvbiwgU3RyZXNzIFRlc3Rpbmcg4oCTIHdpdGggQXBwbGljYXRpb25zIHRvIExvYW4gUmlzayBNYW5hZ2VtZW50IChwcC4gMeKAkzEyKS4gTmV3IFlvcms6IFNwcmluZ2VyLiAgDQpbXjVdOiBEZXZlbG9waW5nLCBWYWxpZGF0aW5nIGFuZCBVc2luZyBJbnRlcm5hbCBSYXRpbmdzIC0gRGUgTGF1cmVudGlzDQpbXjZdOiBDcmVkaXQgUmlzayBNb2RlbGluZyB1c2luZyBFeGNlbCBhbmQgVkJBLCAybmQgRWRpdGlvbiAtIEd1bnRlciBMw7ZlZmZsZXIsIFBldGVyIE4uIFBvc2NoLg0KW143XTogVGhlIEJhc2VsIElJIFJpc2sgUGFyYW1ldGVyczogRXN0aW1hdGlvbiwgVmFsaWRhdGlvbiwgU3RyZXNzIFRlc3Rpbmcg4oCTIHdpdGggQXBwbGljYXRpb25zIHRvIExvYW4gUmlzayBNYW5hZ2VtZW50LCBDaGFwdGVyIDMuIE5ldyBZb3JrOiBTcHJpbmdlci4NClteOF06IENyZWRpdCBSaXNrIFNjb3JlY2FyZHM6IERldmVsb3BpbmcgYW5kIEltcGxlbWVudGluZyBJbnRlbGxpZ2VudCBDcmVkaXQgU2NvcmluZywgYnkgTmFlZW0gU2lkZGlxaSANCg0KDQpgYGB7cn0NCm15LnZhcnMgPC0gZmluYWxuaV9scmdlIyBhIG1hdHJpeCB3aXRoIHlvdXIgMTQgZGlmZmVyZW50IGVudmlyb25tZW50YWwgdmFyaWFibGVzDQpteS52YXJzLnRlc3QgPC0gZmluYWxuaV9scmdlLnRlc3QjIGEgbWF0cml4IHdpdGggeW91ciAxNCBkaWZmZXJlbnQgZW52aXJvbm1lbnRhbCB2YXJpYWJsZXMNCg0KbmFtZXMobXkudmFycylbYygxLDIsNCldPC1jKCJSaWdvcm96bmlfcmFjaW9fcmVkdWtvdmFuZV9tb25ldGFybmVfbGlrdmlkbm9zdGkiLCJSYWNpb19ub3ZjYW5lX2xpa3ZpZG5vc3RpIiwiUmFjaW9fcG9rcmljYV9rYW1hdGFfemFyYWRvbV9wcmVfa2FtYXRhX2lfcG9yZXphIikNCm5hbWVzKG15LnZhcnMudGVzdClbYygxLDIsNCldPC1jKCJSaWdvcm96bmlfcmFjaW9fcmVkdWtvdmFuZV9tb25ldGFybmVfbGlrdmlkbm9zdGkiLCJSYWNpb19ub3ZjYW5lX2xpa3ZpZG5vc3RpIiwiUmFjaW9fcG9rcmljYV9rYW1hdGFfemFyYWRvbV9wcmVfa2FtYXRhX2lfcG9yZXphIikNCg0KbXkudmFycyRkZWZhdWx0Lnk9TlVMTA0KDQpudmFyPC1uY29sKG15LnZhcnMpDQoNCiNjb2xuYW1lcyhteS52YXJzKSA8LSBwYXN0ZSgidmFyIiwgMTpudmFyLCBzZXA9IiIpICMgYWRkIHJvdyBuYW1lcyAidmFyMSIgLSAidmFyMTQiDQpteS5ncmFkLmRhdGEgPC0gMTpudmFyDQpzdW0udmFycyA8LSB2ZWN0b3IoKQ0KYXVjLnAgPC0gdmVjdG9yKCkNCmF1Yy5wcmVkPC12ZWN0b3IoKQ0KY29tYi5tYXQgPC0gbWF0cml4KG51bWVyaWMoMCksIG5yb3c9bnZhciwgbmNvbD0wKSAjIGluaXRpYWxpc2UgdGhlIG1hdHJpeCBjb250YWluaW5nIGFsbCBjb21iaW5hdGlvbnMNCmRpZjwtYXMubnVtZXJpYyhteS52YXJzLnRlc3QkZGVmYXVsdC55KQ0KDQoNCmZvciAoIGkgaW4gMTpudmFyICkgeyAjIGdlbmVyYXRlIGFuZCBzdG9yZSBhbGwgcG9zc2libGUgY29tYmluYXRpb24gb2Ygc3VtcyBvZiB0aGUgMTQgdmFyaWFibGVzDQogIA0KICB0Lm1hdCA8LSBjb21ibihteS5ncmFkLmRhdGEsIG09aSkNCiAgDQogIGNvbWIubWF0IDwtIGNiaW5kKGNvbWIubWF0LCByYmluZCh0Lm1hdCwgbWF0cml4KE5BLCBuY29sPWRpbSh0Lm1hdClbMl0gLCBucm93PW52YXItaSkpKQ0KfQ0KDQpjb2xubXM8LWNvbG5hbWVzKG15LnZhcnMpDQpteS52YXJzJGRlZmF1bHQueT1maW5hbG5pX2xyZ2UkZGVmYXVsdC55DQoNCm51bS5vZi52YXJzIDwtIGFwcGx5KGFzLmRhdGEuZnJhbWUoY29tYi5tYXQpLGMoMikNCiAgICAgICAgICAgICAgICAgICAgICAsIGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgICAgICAgICAgICAgICBzdW0oYXMubnVtZXJpYyghaXMubmEoeCkpKQ0KICAgICAgICAgICAgICAgICAgICAgIH0pDQoNCmZvciAoIGogaW4gMTpkaW0oY29tYi5tYXQpWzJdICkgeyAjIGNhbGN1bGF0ZSBhbmQgc3RvcmUgdGhlIFIyIGZvciBhbGwgY29tYmluYXRpb25zDQogIA0KICAjc3VtLnZlYyA8LSByb3dTdW1zKG15LnZhcnNbLCBjb21iLm1hdFssIGpdXSwgbmEucm09VFJVRSkNCiNicm93c2VyKCkNCiAgc3VtLnZhcnNbal0gPC0gcGFzdGUoIGNvbG5tc1tjKG5hLm9taXQoY29tYi5tYXRbLCBqXSkpXSwgDQogICAgY29sbGFwc2U9IisiKQ0KICByZWxhY2lqYT1hcy5mb3JtdWxhKHBhc3RlKCJkZWZhdWx0LnkgfiAiLHN1bS52YXJzW2pdLHNlcCA9ICIiKSkNCiAgbW9kZWwgPSBzcGVlZGdsbShyZWxhY2lqYSwNCiAgICAgICAgICAgICAgICAgICBkYXRhID0gbXkudmFycywNCiAgICAgICAgICAgICAgICAgICB5PVRSVUUsDQogICAgICAgICAgICAgICAgICAgZml0dGVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IikpDQojaWYoaj09MTMpIGJyb3dzZXIoKQ0KICBtb2RlbC5kYXRhLmZyYW1lPWRhdGEuZnJhbWUoZml0PWZpdHRlZC52YWx1ZXMobW9kZWwpLCBkaWY9bW9kZWwkeSkNCiAgYXVjLnBbal0gPC0gYXVjX3JvYyhhcy5udW1lcmljKG1vZGVsLmRhdGEuZnJhbWUkZml0KSxhcy5udW1lcmljKG1vZGVsLmRhdGEuZnJhbWUkZGlmKSkNCiAgDQogIG1vZGVsLnByZWQ8LWFzLm51bWVyaWMocHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9bXkudmFycy50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQogIGF1Yy5wcmVkW2pdPC1hdWNfcm9jKCBtb2RlbC5wcmVkLGRpZikNCiAgDQogIGlmKGogJWluJSByb3VuZChzZXEoZnJvbT0xLCB0bz1kaW0oY29tYi5tYXQpWzJdLGxlbmd0aC5vdXQgPSAxMDApKSkgcHJpbnQoai9kaW0oY29tYi5tYXQpWzJdKQ0KICAjcHJpbnQoaikNCiAgDQp9DQoNCg0KDQpyZXN1bHQuZnJhbWUgPC0gZGF0YS5mcmFtZShjb21iaW5hdGlvbj1zdW0udmFycywgYXVjLnA9YXVjLnAsIGF1Yy50ZXN0PWF1Yy5wcmVkLG51bV9vZl92YXJzPW51bS5vZi52YXJzKQ0KDQpyZXN1bHQuZnJhbWUuc29ydGVkIDwtIHJlc3VsdC5mcmFtZVtvcmRlcigtYXVjLnByZWQsLWF1Yy5wLC1udW0ub2YudmFycyksIF0NCg0KICBoZWFkKHJlc3VsdC5mcmFtZS5zb3J0ZWRbcmVzdWx0LmZyYW1lLnNvcnRlZCRhdWMudGVzdD4wLjc1ICYgcmVzdWx0LmZyYW1lLnNvcnRlZCRhdWMucD4wLjc1ICYgcmVzdWx0LmZyYW1lLnNvcnRlZCRudW1fb2ZfdmFycz09NixdLCBuPTEwMCkgIyB0aGUgMTAgImJlc3QiIGNvbWJpbmF0aW9ucw0KYGBgDQoNCg0KS29uYWNubyBiaXJhbW8gb3Z1IGZvcm11bHU6ICANCg0KDQogZ2xtKGZvcm11bGEgPWRlZmF1bHQueX5gUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbylgK1N0ZXBlbl96YWR1emVub3N0aStHb3Rvdmluc2tpX2Npa2x1c18xK1ZyZW1lX25hcGxhdGVfcG90cmF6aXZhbmphK1N0b3BhX3ByaW5vc2FfbmFfc29wc3R2ZW5pX2thcGl0YWxfcHJlX29wb3Jleml2YW5qYStDZW5hX3R1ZGppaF9penZvcmFfc3JlZHN0YXZhLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIA0KICAgIGRhdGEgPSBmaW5hbG5pX2xyZ2UpYCAgDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=